From 9e4258bc460082385428b9aa3ac87b96ea4aced9 Mon Sep 17 00:00:00 2001 From: Nuno Cruces Date: Tue, 25 Mar 2025 12:45:27 +0000 Subject: [PATCH] Better fix #249. --- config.go | 6 +++--- conn.go | 4 ++-- vfs/cksm.go | 24 +++++++++++++++--------- vtab.go | 6 ++++-- 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/config.go b/config.go index d52cc05..decea18 100644 --- a/config.go +++ b/config.go @@ -279,6 +279,8 @@ func (c *Conn) WALCheckpoint(schema string, mode CheckpointMode) (nLog, nCkpt in nLogPtr := c.arena.new(ptrlen) nCkptPtr := c.arena.new(ptrlen) schemaPtr := c.arena.string(schema) + + c.checkInterrupt() rc := res_t(c.call("sqlite3_wal_checkpoint_v2", stk_t(c.handle), stk_t(schemaPtr), stk_t(mode), stk_t(nLogPtr), stk_t(nCkptPtr))) @@ -350,8 +352,6 @@ func (c *Conn) HardHeapLimit(n int64) int64 { } // EnableChecksums enables checksums on a database. -// If the database is in WAL mode, -// you should shutdown and reopen all database connections before continuing. // // https://sqlite.org/cksumvfs.html func (c *Conn) EnableChecksums(schema string) error { @@ -390,6 +390,6 @@ func (c *Conn) EnableChecksums(schema string) error { } // Checkpoint the WAL. - _, _, err = c.WALCheckpoint(schema, CHECKPOINT_RESTART) + _, _, err = c.WALCheckpoint(schema, CHECKPOINT_FULL) return err } diff --git a/conn.go b/conn.go index 2ea16a2..06b6637 100644 --- a/conn.go +++ b/conn.go @@ -185,10 +185,10 @@ func (c *Conn) Close() error { // https://sqlite.org/c3ref/exec.html func (c *Conn) Exec(sql string) error { defer c.arena.mark()() - sqlPtr := c.arena.string(sql) + textPtr := c.arena.string(sql) c.checkInterrupt() - rc := res_t(c.call("sqlite3_exec", stk_t(c.handle), stk_t(sqlPtr), 0, 0, 0)) + rc := res_t(c.call("sqlite3_exec", stk_t(c.handle), stk_t(textPtr), 0, 0, 0)) return c.error(rc, sql) } diff --git a/vfs/cksm.go b/vfs/cksm.go index 1610549..0ff7b6f 100644 --- a/vfs/cksm.go +++ b/vfs/cksm.go @@ -49,9 +49,7 @@ func (c cksmFile) ReadAt(p []byte, off int64) (n int, err error) { n, err = c.File.ReadAt(p, off) p = p[:n] - // SQLite is reading the header of a database file. - if c.isDB && off == 0 && len(p) >= 100 && - bytes.HasPrefix(p, []byte("SQLite format 3\000")) { + if isHeader(c.isDB, p, off) { c.init((*[100]byte)(p)) } @@ -67,9 +65,7 @@ func (c cksmFile) ReadAt(p []byte, off int64) (n int, err error) { } func (c cksmFile) WriteAt(p []byte, off int64) (n int, err error) { - // SQLite is writing the first page of a database file. - if (!c.isDB || off == 0) && sql3util.ValidPageSize(len(p)) && - bytes.HasPrefix(p, []byte("SQLite format 3\000")) { + if isHeader(c.isDB, p, off) { c.init((*[100]byte)(p)) } @@ -116,9 +112,11 @@ func (c cksmFile) fileControl(ctx context.Context, mod api.Module, op _FcntlOpco c.inCkpt = true case _FCNTL_CKPT_DONE: c.inCkpt = false - } - if rc := vfsFileControlImpl(ctx, mod, c, op, pArg); rc != _NOTFOUND { - return rc + case _FCNTL_PRAGMA: + rc := vfsFileControlImpl(ctx, mod, c, op, pArg) + if rc != _NOTFOUND { + return rc + } } return vfsFileControlImpl(ctx, mod, c.File, op, pArg) } @@ -135,6 +133,14 @@ func (f *cksmFlags) init(header *[100]byte) { } } +func isHeader(isDB bool, p []byte, off int64) bool { + check := sql3util.ValidPageSize(len(p)) + if isDB { + check = off == 0 && len(p) >= 100 + } + return check && bytes.HasPrefix(p, []byte("SQLite format 3\000")) +} + func cksmCompute(a []byte) (cksm [8]byte) { var s1, s2 uint32 for len(a) >= 8 { diff --git a/vtab.go b/vtab.go index f4282d9..1db142c 100644 --- a/vtab.go +++ b/vtab.go @@ -80,8 +80,10 @@ func implements[T any](typ reflect.Type) bool { // https://sqlite.org/c3ref/declare_vtab.html func (c *Conn) DeclareVTab(sql string) error { defer c.arena.mark()() - sqlPtr := c.arena.string(sql) - rc := res_t(c.call("sqlite3_declare_vtab", stk_t(c.handle), stk_t(sqlPtr))) + textPtr := c.arena.string(sql) + + c.checkInterrupt() + rc := res_t(c.call("sqlite3_declare_vtab", stk_t(c.handle), stk_t(textPtr))) return c.error(rc) }