1
0
Fork 0

Merge branch 'master' into no-disk-during-restore

master
Philip O'Toole 4 years ago
commit b83b2b241d

@ -449,10 +449,20 @@ func (db *DB) Backup(path string) error {
}(dstDB, &err)
if err := copyDatabase(dstDB.sqlite3conn, db.sqlite3conn); err != nil {
return err
return fmt.Errorf("backup database: %s", err)
}
return nil
}
return err
// Copy copies the contents of the database to the given database. All other
// attributes of the given database remain untouched e.g. whether it's an
// on-disk database. This function can be called when changes to the source
// database are in flight.
func (db *DB) Copy(dstDB *DB) error {
if err := copyDatabase(dstDB.sqlite3conn, db.sqlite3conn); err != nil {
return fmt.Errorf("copy database: %s", err)
}
return nil
}
// Serialize returns a byte slice representation of the SQLite database. For

@ -934,24 +934,20 @@ func Test_Backup(t *testing.T) {
t.Fatalf("failed to insert records: %s", err.Error())
}
dstDB, err := ioutil.TempFile("", "rqlilte-bak-")
if err != nil {
t.Fatalf("failed to create temp file: %s", err.Error())
}
dstDB.Close()
defer os.Remove(dstDB.Name())
dstDB := mustTempFile()
defer os.Remove(dstDB)
err = db.Backup(dstDB.Name())
err = db.Backup(dstDB)
if err != nil {
t.Fatalf("failed to backup database: %s", err.Error())
}
newDB, err := Open(dstDB.Name())
newDB, err := Open(dstDB)
if err != nil {
t.Fatalf("failed to open backup database: %s", err.Error())
}
defer newDB.Close()
defer os.Remove(dstDB.Name())
defer os.Remove(dstDB)
ro, err := newDB.QueryStringStmt(`SELECT * FROM foo`)
if err != nil {
t.Fatalf("failed to query table: %s", err.Error())
@ -961,6 +957,60 @@ func Test_Backup(t *testing.T) {
}
}
func Test_Copy(t *testing.T) {
srcDB, path := mustCreateDatabase()
defer srcDB.Close()
defer os.Remove(path)
_, err := srcDB.ExecuteStringStmt("CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name TEXT)")
if err != nil {
t.Fatalf("failed to create table: %s", err.Error())
}
req := &command.Request{
Transaction: true,
Statements: []*command.Statement{
{
Sql: `INSERT INTO foo(id, name) VALUES(1, "fiona")`,
},
{
Sql: `INSERT INTO foo(id, name) VALUES(2, "fiona")`,
},
{
Sql: `INSERT INTO foo(id, name) VALUES(3, "fiona")`,
},
{
Sql: `INSERT INTO foo(id, name) VALUES(4, "fiona")`,
},
},
}
_, err = srcDB.Execute(req, false)
if err != nil {
t.Fatalf("failed to insert records: %s", err.Error())
}
dstFile := mustTempFile()
defer os.Remove(dstFile)
dstDB, err := Open(dstFile)
if err != nil {
t.Fatalf("failed to open destination database: %s", err)
}
defer dstDB.Close()
err = srcDB.Copy(dstDB)
if err != nil {
t.Fatalf("failed to copy database: %s", err.Error())
}
ro, err := dstDB.QueryStringStmt(`SELECT * FROM foo`)
if err != nil {
t.Fatalf("failed to query table: %s", err.Error())
}
if exp, got := `[{"columns":["id","name"],"types":["integer","text"],"values":[[1,"fiona"],[2,"fiona"],[3,"fiona"],[4,"fiona"]]}]`, asJSON(ro); exp != got {
t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
}
}
func Test_Serialize(t *testing.T) {
db, path := mustCreateDatabase()
defer db.Close()
@ -1132,38 +1182,28 @@ func Test_DumpMemory(t *testing.T) {
func mustCreateDatabase() (*DB, string) {
var err error
f, err := ioutil.TempFile("", "rqlite-test-")
if err != nil {
panic("failed to create temp file")
}
f.Close()
db, err := Open(f.Name())
f := mustTempFile()
db, err := Open(f)
if err != nil {
panic("failed to open database")
}
return db, f.Name()
return db, f
}
func mustWriteAndOpenDatabase(b []byte) (*DB, string) {
var err error
f, err := ioutil.TempFile("", "rqlilte-test-write-")
if err != nil {
panic("failed to create temp file")
}
f.Close()
err = ioutil.WriteFile(f.Name(), b, 0660)
f := mustTempFile()
err = ioutil.WriteFile(f, b, 0660)
if err != nil {
panic("failed to write file")
}
db, err := Open(f.Name())
db, err := Open(f)
if err != nil {
panic("failed to open database")
}
return db, f.Name()
return db, f
}
// mustExecute executes a statement, and panics on failure. Used for statements
@ -1191,3 +1231,14 @@ func asJSON(v interface{}) string {
}
return string(b)
}
// mustTempFile returns a path to a temporary file in directory dir. It is up to the
// caller to remove the file once it is no longer needed.
func mustTempFile() string {
tmpfile, err := ioutil.TempFile("", "rqlite-db-test")
if err != nil {
panic(err.Error())
}
tmpfile.Close()
return tmpfile.Name()
}

@ -17,7 +17,7 @@ require (
github.com/mattn/go-sqlite3 v2.0.3+incompatible
github.com/mkideal/cli v0.2.3
github.com/mkideal/pkg v0.1.2
github.com/rqlite/go-sqlite3 v1.19.0
github.com/rqlite/go-sqlite3 v1.20.0
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
golang.org/x/net v0.0.0-20200707034311-ab3426394381
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect

@ -200,6 +200,8 @@ github.com/rqlite/go-sqlite3 v1.18.0 h1:nRIqbrChAY87Re6XwbqjJyzzeijnY5Y1x/SJn0qU
github.com/rqlite/go-sqlite3 v1.18.0/go.mod h1:ml55MVv28UP7V8zrxILd2EsrI6Wfsz76YSskpg08Ut4=
github.com/rqlite/go-sqlite3 v1.19.0 h1:0EhyoFWxHQgFoGjP7oXVJ5QFjXCGk0whOp7tBqGOF6k=
github.com/rqlite/go-sqlite3 v1.19.0/go.mod h1:ml55MVv28UP7V8zrxILd2EsrI6Wfsz76YSskpg08Ut4=
github.com/rqlite/go-sqlite3 v1.20.0 h1:3Anrr2N9C8KJfc3VF1tJPjoSbSIBEFIwhacTBQAj3Jw=
github.com/rqlite/go-sqlite3 v1.20.0/go.mod h1:ml55MVv28UP7V8zrxILd2EsrI6Wfsz76YSskpg08Ut4=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=

Loading…
Cancel
Save