-
-
Notifications
You must be signed in to change notification settings - Fork 18
/
backup.go
95 lines (86 loc) · 3.77 KB
/
backup.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
// Copyright 2023 Roxy Light
// SPDX-License-Identifier: ISC
package sqlite
import (
"fmt"
"modernc.org/libc"
lib "modernc.org/sqlite/lib"
)
// A Backup represents a copy operation between two database connections.
// See https://www.sqlite.org/backup.html for more details.
type Backup struct {
tls *libc.TLS
ptr uintptr
}
// NewBackup creates a [Backup] that copies from one connection to another.
// The database name is "main" or "" for the main database,
// "temp" for the temporary database,
// or the name specified after the AS keyword in an ATTACH statement for an attached database.
// If src and dst are the same connection, NewBackup will return an error.
// It is the caller's responsibility to call [Backup.Close] on the returned Backup object.
func NewBackup(dst *Conn, dstName string, src *Conn, srcName string) (*Backup, error) {
cDstName, freeCDstName, err := cDBName(dstName)
if err != nil {
return nil, fmt.Errorf("sqlite: new backup: %w", err)
}
defer freeCDstName()
cSrcName, freeCSrcName, err := cDBName(srcName)
if err != nil {
return nil, fmt.Errorf("sqlite: new backup: %w", err)
}
defer freeCSrcName()
backupPtr := lib.Xsqlite3_backup_init(dst.tls, dst.conn, cDstName, src.conn, cSrcName)
if backupPtr == 0 {
res := ResultCode(lib.Xsqlite3_errcode(dst.tls, dst.conn))
return nil, fmt.Errorf("sqlite: new backup: %w", dst.extreserr(res))
}
return &Backup{dst.tls, backupPtr}, nil
}
// Step copies up to n pages from the source database to the destination database.
// If n is negative, all remaining source pages are copied.
// more will be true if there are pages still remaining to be copied.
// Step may return both an error and that more pages are still remaining:
// this indicates the error is temporary and that Step can be retried.
func (b *Backup) Step(n int) (more bool, err error) {
res := ResultCode(lib.Xsqlite3_backup_step(b.tls, b.ptr, int32(n)))
switch res {
case ResultOK:
return true, nil
case ResultDone:
return false, nil
case ResultBusy, ResultLocked:
// SQLITE_BUSY and SQLITE_LOCKED are retriable errors.
return true, fmt.Errorf("sqlite: backup step: %w", res.ToError())
default:
return false, fmt.Errorf("sqlite: backup step: %w", res.ToError())
}
}
// Remaining returns the number of pages still to be backed up
// at the conclusion of the most recent call to [Backup.Step].
// The return value of Remaining before calling [Backup.Step] is undefined.
// If the source database is modified in a way that changes the number of pages remaining,
// that change is not reflected in the output until after the next call to [Backup.Step].
func (b *Backup) Remaining() int {
return int(lib.Xsqlite3_backup_remaining(b.tls, b.ptr))
}
// PageCount returns the total number of pages in the source database
// at the conclusion of the most recent call to [Backup.Step].
// The return value of PageCount before calling [Backup.Step] is undefined.
// If the source database is modified in a way that changes the size of the source database,
// that change is not reflected in the output until after the next call to [Backup.Step].
func (b *Backup) PageCount() int {
return int(lib.Xsqlite3_backup_pagecount(b.tls, b.ptr))
}
// Close releases all resources associated with the backup.
// If [Backup.Step] has not yet returned (false, nil),
// then any active write transaction on the destination database is rolled back.
func (b *Backup) Close() error {
// The error from sqlite3_backup_finish indicates whether
// a previous call to sqlite3_backup_step returned an error.
// Since we're assuming that the caller will handle errors as they arise,
// we always return nil from Close.
// However, I'm not fully confident that Close will always be infallible,
// so I'm not documenting this as part of the API.
lib.Xsqlite3_backup_finish(b.tls, b.ptr)
return nil
}