mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-11 21:49:13 +00:00
Towards shared modules: backup.
This commit is contained in:
184
api.go
184
api.go
@@ -22,96 +22,106 @@ func (module *module) loadAPI() (err error) {
|
||||
return module.mem.readUint32(uint32(global.Get()))
|
||||
}
|
||||
|
||||
{
|
||||
module.api = sqliteAPI{
|
||||
free: getFun("free"),
|
||||
malloc: getFun("malloc"),
|
||||
destructor: uint64(getVal("malloc_destructor")),
|
||||
errcode: getFun("sqlite3_errcode"),
|
||||
errstr: getFun("sqlite3_errstr"),
|
||||
errmsg: getFun("sqlite3_errmsg"),
|
||||
erroff: getFun("sqlite3_error_offset"),
|
||||
open: getFun("sqlite3_open_v2"),
|
||||
close: getFun("sqlite3_close"),
|
||||
prepare: getFun("sqlite3_prepare_v3"),
|
||||
finalize: getFun("sqlite3_finalize"),
|
||||
reset: getFun("sqlite3_reset"),
|
||||
step: getFun("sqlite3_step"),
|
||||
exec: getFun("sqlite3_exec"),
|
||||
clearBindings: getFun("sqlite3_clear_bindings"),
|
||||
bindCount: getFun("sqlite3_bind_parameter_count"),
|
||||
bindIndex: getFun("sqlite3_bind_parameter_index"),
|
||||
bindName: getFun("sqlite3_bind_parameter_name"),
|
||||
bindNull: getFun("sqlite3_bind_null"),
|
||||
bindInteger: getFun("sqlite3_bind_int64"),
|
||||
bindFloat: getFun("sqlite3_bind_double"),
|
||||
bindText: getFun("sqlite3_bind_text64"),
|
||||
bindBlob: getFun("sqlite3_bind_blob64"),
|
||||
bindZeroBlob: getFun("sqlite3_bind_zeroblob64"),
|
||||
columnCount: getFun("sqlite3_column_count"),
|
||||
columnName: getFun("sqlite3_column_name"),
|
||||
columnType: getFun("sqlite3_column_type"),
|
||||
columnInteger: getFun("sqlite3_column_int64"),
|
||||
columnFloat: getFun("sqlite3_column_double"),
|
||||
columnText: getFun("sqlite3_column_text"),
|
||||
columnBlob: getFun("sqlite3_column_blob"),
|
||||
columnBytes: getFun("sqlite3_column_bytes"),
|
||||
autocommit: getFun("sqlite3_get_autocommit"),
|
||||
lastRowid: getFun("sqlite3_last_insert_rowid"),
|
||||
changes: getFun("sqlite3_changes64"),
|
||||
blobOpen: getFun("sqlite3_blob_open"),
|
||||
blobClose: getFun("sqlite3_blob_close"),
|
||||
blobReopen: getFun("sqlite3_blob_reopen"),
|
||||
blobBytes: getFun("sqlite3_blob_bytes"),
|
||||
blobRead: getFun("sqlite3_blob_read"),
|
||||
blobWrite: getFun("sqlite3_blob_write"),
|
||||
interrupt: getVal("sqlite3_interrupt_offset"),
|
||||
}
|
||||
module.api = sqliteAPI{
|
||||
free: getFun("free"),
|
||||
malloc: getFun("malloc"),
|
||||
destructor: uint64(getVal("malloc_destructor")),
|
||||
errcode: getFun("sqlite3_errcode"),
|
||||
errstr: getFun("sqlite3_errstr"),
|
||||
errmsg: getFun("sqlite3_errmsg"),
|
||||
erroff: getFun("sqlite3_error_offset"),
|
||||
open: getFun("sqlite3_open_v2"),
|
||||
close: getFun("sqlite3_close"),
|
||||
closeZombie: getFun("sqlite3_close_v2"),
|
||||
prepare: getFun("sqlite3_prepare_v3"),
|
||||
finalize: getFun("sqlite3_finalize"),
|
||||
reset: getFun("sqlite3_reset"),
|
||||
step: getFun("sqlite3_step"),
|
||||
exec: getFun("sqlite3_exec"),
|
||||
clearBindings: getFun("sqlite3_clear_bindings"),
|
||||
bindCount: getFun("sqlite3_bind_parameter_count"),
|
||||
bindIndex: getFun("sqlite3_bind_parameter_index"),
|
||||
bindName: getFun("sqlite3_bind_parameter_name"),
|
||||
bindNull: getFun("sqlite3_bind_null"),
|
||||
bindInteger: getFun("sqlite3_bind_int64"),
|
||||
bindFloat: getFun("sqlite3_bind_double"),
|
||||
bindText: getFun("sqlite3_bind_text64"),
|
||||
bindBlob: getFun("sqlite3_bind_blob64"),
|
||||
bindZeroBlob: getFun("sqlite3_bind_zeroblob64"),
|
||||
columnCount: getFun("sqlite3_column_count"),
|
||||
columnName: getFun("sqlite3_column_name"),
|
||||
columnType: getFun("sqlite3_column_type"),
|
||||
columnInteger: getFun("sqlite3_column_int64"),
|
||||
columnFloat: getFun("sqlite3_column_double"),
|
||||
columnText: getFun("sqlite3_column_text"),
|
||||
columnBlob: getFun("sqlite3_column_blob"),
|
||||
columnBytes: getFun("sqlite3_column_bytes"),
|
||||
autocommit: getFun("sqlite3_get_autocommit"),
|
||||
lastRowid: getFun("sqlite3_last_insert_rowid"),
|
||||
changes: getFun("sqlite3_changes64"),
|
||||
blobOpen: getFun("sqlite3_blob_open"),
|
||||
blobClose: getFun("sqlite3_blob_close"),
|
||||
blobReopen: getFun("sqlite3_blob_reopen"),
|
||||
blobBytes: getFun("sqlite3_blob_bytes"),
|
||||
blobRead: getFun("sqlite3_blob_read"),
|
||||
blobWrite: getFun("sqlite3_blob_write"),
|
||||
backupInit: getFun("sqlite3_backup_init"),
|
||||
backupStep: getFun("sqlite3_backup_step"),
|
||||
backupFinish: getFun("sqlite3_backup_finish"),
|
||||
backupRemaining: getFun("sqlite3_backup_remaining"),
|
||||
backupPageCount: getFun("sqlite3_backup_pagecount"),
|
||||
interrupt: getVal("sqlite3_interrupt_offset"),
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
type sqliteAPI struct {
|
||||
free api.Function
|
||||
malloc api.Function
|
||||
destructor uint64
|
||||
errcode api.Function
|
||||
errstr api.Function
|
||||
errmsg api.Function
|
||||
erroff api.Function
|
||||
open api.Function
|
||||
close api.Function
|
||||
prepare api.Function
|
||||
finalize api.Function
|
||||
reset api.Function
|
||||
step api.Function
|
||||
exec api.Function
|
||||
clearBindings api.Function
|
||||
bindNull api.Function
|
||||
bindCount api.Function
|
||||
bindIndex api.Function
|
||||
bindName api.Function
|
||||
bindInteger api.Function
|
||||
bindFloat api.Function
|
||||
bindText api.Function
|
||||
bindBlob api.Function
|
||||
bindZeroBlob api.Function
|
||||
columnCount api.Function
|
||||
columnName api.Function
|
||||
columnType api.Function
|
||||
columnInteger api.Function
|
||||
columnFloat api.Function
|
||||
columnText api.Function
|
||||
columnBlob api.Function
|
||||
columnBytes api.Function
|
||||
autocommit api.Function
|
||||
lastRowid api.Function
|
||||
changes api.Function
|
||||
blobOpen api.Function
|
||||
blobClose api.Function
|
||||
blobReopen api.Function
|
||||
blobBytes api.Function
|
||||
blobRead api.Function
|
||||
blobWrite api.Function
|
||||
interrupt uint32
|
||||
free api.Function
|
||||
malloc api.Function
|
||||
destructor uint64
|
||||
errcode api.Function
|
||||
errstr api.Function
|
||||
errmsg api.Function
|
||||
erroff api.Function
|
||||
open api.Function
|
||||
close api.Function
|
||||
closeZombie api.Function
|
||||
prepare api.Function
|
||||
finalize api.Function
|
||||
reset api.Function
|
||||
step api.Function
|
||||
exec api.Function
|
||||
clearBindings api.Function
|
||||
bindNull api.Function
|
||||
bindCount api.Function
|
||||
bindIndex api.Function
|
||||
bindName api.Function
|
||||
bindInteger api.Function
|
||||
bindFloat api.Function
|
||||
bindText api.Function
|
||||
bindBlob api.Function
|
||||
bindZeroBlob api.Function
|
||||
columnCount api.Function
|
||||
columnName api.Function
|
||||
columnType api.Function
|
||||
columnInteger api.Function
|
||||
columnFloat api.Function
|
||||
columnText api.Function
|
||||
columnBlob api.Function
|
||||
columnBytes api.Function
|
||||
autocommit api.Function
|
||||
lastRowid api.Function
|
||||
changes api.Function
|
||||
blobOpen api.Function
|
||||
blobClose api.Function
|
||||
blobReopen api.Function
|
||||
blobBytes api.Function
|
||||
blobRead api.Function
|
||||
blobWrite api.Function
|
||||
backupInit api.Function
|
||||
backupStep api.Function
|
||||
backupFinish api.Function
|
||||
backupRemaining api.Function
|
||||
backupPageCount api.Function
|
||||
interrupt uint32
|
||||
}
|
||||
|
||||
69
backup.go
Normal file
69
backup.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package sqlite3
|
||||
|
||||
// Backup is a handle to an open BLOB.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/backup.html
|
||||
type Backup struct {
|
||||
c *Conn
|
||||
handle uint32
|
||||
}
|
||||
|
||||
// BackupInit initializes a backup operation to copy the content of one database into another.
|
||||
//
|
||||
// BackupInit calls [Conn.Open] to open the SQLite database file dstURI,
|
||||
// then initializes a backup that copies the content of srcDB to the "main" database in dstURI.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupinit
|
||||
func (c *Conn) BackupInit(srcDB, dstURI string) (*Backup, error) {
|
||||
return c.backupInit(srcDB, "main", 0)
|
||||
}
|
||||
|
||||
func (c *Conn) backupInit(srcDB, dstDB string, handle uint32) (*Backup, error) {
|
||||
return nil, notImplErr
|
||||
}
|
||||
|
||||
// Close finishes a backup operation.
|
||||
//
|
||||
// It is safe to close a nil, zero or closed Backup.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupfinish
|
||||
func (b *Backup) Close() error {
|
||||
if b == nil || b.handle == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
r := b.c.call(b.c.api.backupFinish, uint64(b.handle))
|
||||
|
||||
b.handle = 0
|
||||
return b.c.error(r[0])
|
||||
}
|
||||
|
||||
// Step copies up to nPage pages between the source and destination databases.
|
||||
// If nPage is negative, all remaining source pages are copied.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupstep
|
||||
func (b *Backup) Step(nPage int) (done bool, err error) {
|
||||
r := b.c.call(b.c.api.backupStep, uint64(b.handle), uint64(nPage))
|
||||
if r[0] == _DONE {
|
||||
return true, nil
|
||||
}
|
||||
return false, b.c.error(r[0])
|
||||
}
|
||||
|
||||
// Remaining returns the number of pages still to be backed up
|
||||
// at the conclusion of the most recent [Backup.Step].
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupremaining
|
||||
func (b *Backup) Remaining() int {
|
||||
r := b.c.call(b.c.api.backupRemaining, uint64(b.handle))
|
||||
return int(r[0])
|
||||
}
|
||||
|
||||
// PageCount returns the total number of pages in the source database
|
||||
// at the conclusion of the most recent [Backup.Step].
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backuppagecount
|
||||
func (b *Backup) PageCount() int {
|
||||
r := b.c.call(b.c.api.backupFinish, uint64(b.handle))
|
||||
return int(r[0])
|
||||
}
|
||||
45
conn.go
45
conn.go
@@ -33,7 +33,7 @@ type Conn struct {
|
||||
|
||||
// Open calls [OpenFlags] with [OPEN_READWRITE], [OPEN_CREATE] and [OPEN_URI].
|
||||
func Open(filename string) (*Conn, error) {
|
||||
return openFlags(filename, OPEN_READWRITE|OPEN_CREATE|OPEN_URI)
|
||||
return newConn(filename, OPEN_READWRITE|OPEN_CREATE|OPEN_URI)
|
||||
}
|
||||
|
||||
// OpenFlags opens an SQLite database file as specified by the filename argument.
|
||||
@@ -44,10 +44,10 @@ func Open(filename string) (*Conn, error) {
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/open.html
|
||||
func OpenFlags(filename string, flags OpenFlag) (*Conn, error) {
|
||||
return openFlags(filename, flags)
|
||||
return newConn(filename, flags)
|
||||
}
|
||||
|
||||
func openFlags(filename string, flags OpenFlag) (conn *Conn, err error) {
|
||||
func newConn(filename string, flags OpenFlag) (conn *Conn, err error) {
|
||||
ctx := context.Background()
|
||||
mod, err := instantiateModule()
|
||||
if err != nil {
|
||||
@@ -68,16 +68,24 @@ func openFlags(filename string, flags OpenFlag) (conn *Conn, err error) {
|
||||
mem: &mod.mem,
|
||||
}
|
||||
c.arena = c.newArena(1024)
|
||||
c.handle, err = c.openDB(filename, flags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *Conn) openDB(filename string, flags OpenFlag) (uint32, error) {
|
||||
defer c.arena.reset()
|
||||
connPtr := c.arena.new(ptrlen)
|
||||
namePtr := c.arena.string(filename)
|
||||
|
||||
r := c.call(c.api.open, uint64(namePtr), uint64(connPtr), uint64(flags), 0)
|
||||
|
||||
c.handle = c.mem.readUint32(connPtr)
|
||||
if err := c.error(r[0]); err != nil {
|
||||
return nil, err
|
||||
handle := c.mem.readUint32(connPtr)
|
||||
if err := c.mod.error(r[0], handle); err != nil {
|
||||
c.closeDB(handle)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if flags|OPEN_URI != 0 && strings.HasPrefix(filename, "file:") {
|
||||
@@ -90,11 +98,22 @@ func openFlags(filename string, flags OpenFlag) (conn *Conn, err error) {
|
||||
pragmas.WriteByte(';')
|
||||
}
|
||||
}
|
||||
if err := c.Exec(pragmas.String()); err != nil {
|
||||
return nil, fmt.Errorf("sqlite3: invalid _pragma: %w", err)
|
||||
|
||||
pragmaPtr := c.arena.string(pragmas.String())
|
||||
r := c.call(c.api.exec, uint64(handle), uint64(pragmaPtr), 0, 0, 0)
|
||||
if err := c.mod.error(r[0], handle, pragmas.String()); err != nil {
|
||||
c.closeDB(handle)
|
||||
return 0, fmt.Errorf("sqlite3: invalid _pragma: %w", err)
|
||||
}
|
||||
}
|
||||
return c, nil
|
||||
return handle, nil
|
||||
}
|
||||
|
||||
func (c *Conn) closeDB(handle uint32) {
|
||||
r := c.call(c.api.closeZombie, uint64(c.handle))
|
||||
if err := c.mod.error(r[0], handle); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Close closes the database connection.
|
||||
@@ -312,6 +331,10 @@ func (c *Conn) Pragma(str string) []string {
|
||||
}
|
||||
|
||||
func (c *Conn) error(rc uint64, sql ...string) error {
|
||||
return c.mod.error(rc, c.handle, sql...)
|
||||
}
|
||||
|
||||
func (c *module) error(rc uint64, handle uint32, sql ...string) error {
|
||||
if rc == _OK {
|
||||
return nil
|
||||
}
|
||||
@@ -329,13 +352,13 @@ func (c *Conn) error(rc uint64, sql ...string) error {
|
||||
err.str = c.mem.readString(uint32(r[0]), _MAX_STRING)
|
||||
}
|
||||
|
||||
r, _ = c.api.errmsg.Call(c.ctx, uint64(c.handle))
|
||||
r, _ = c.api.errmsg.Call(c.ctx, uint64(handle))
|
||||
if r != nil {
|
||||
err.msg = c.mem.readString(uint32(r[0]), _MAX_STRING)
|
||||
}
|
||||
|
||||
if sql != nil {
|
||||
r, _ = c.api.erroff.Call(c.ctx, uint64(c.handle))
|
||||
r, _ = c.api.erroff.Call(c.ctx, uint64(handle))
|
||||
if r != nil && r[0] != math.MaxUint32 {
|
||||
err.sql = sql[0][r[0]:]
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -7,6 +7,7 @@ sqlite3_errmsg
|
||||
sqlite3_error_offset
|
||||
sqlite3_open_v2
|
||||
sqlite3_close
|
||||
sqlite3_close_v2
|
||||
sqlite3_prepare_v3
|
||||
sqlite3_finalize
|
||||
sqlite3_reset
|
||||
|
||||
3
tests/mptest/testdata/build.sh
vendored
3
tests/mptest/testdata/build.sh
vendored
@@ -22,5 +22,4 @@ zig cc --target=wasm32-wasi -flto -g0 -Os \
|
||||
-DSQLITE_DEFAULT_LOCKING_MODE=0 \
|
||||
-DHAVE_USLEEP -DSQLITE_NO_SYNC \
|
||||
-DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
-D_WASI_EMULATED_GETPID -lwasi-emulated-getpid \
|
||||
$(awk '{print "-Wl,--export="$0}' ../../../sqlite3/exports.txt)
|
||||
-D_WASI_EMULATED_GETPID -lwasi-emulated-getpid
|
||||
4
tests/mptest/testdata/mptest.wasm
vendored
4
tests/mptest/testdata/mptest.wasm
vendored
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:430afdac4d212a6e4b662db46c1bbb5bfb3d601770ae493beb0420a302dc3131
|
||||
size 1080243
|
||||
oid sha256:e155ad9a9723b2eb2c0d187cbd079f4111931064a62ba0cb30ff4e4242bf5efd
|
||||
size 1077263
|
||||
|
||||
Reference in New Issue
Block a user