Skip to content

Commit 8e327a9

Browse files
committed
VFS pragma.
1 parent 09a0ce0 commit 8e327a9

File tree

6 files changed

+97
-6
lines changed

6 files changed

+97
-6
lines changed

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ It also benefits greatly from [SQLite's](https://sqlite.org/testing.html) and
8989

9090
Every commit is [tested](.github/workflows/test.yml) on
9191
Linux (amd64/arm64/386/riscv64), macOS (amd64/arm64), Windows, FreeBSD and illumos.
92-
9392
The Go VFS is tested by running SQLite's
9493
[mptest](https://github.com/sqlite/sqlite/blob/master/mptest/mptest.c).
9594

conn.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ func (c *Conn) Prepare(sql string) (stmt *Stmt, tail string, err error) {
176176
//
177177
// https://sqlite.org/c3ref/prepare.html
178178
func (c *Conn) PrepareFlags(sql string, flags PrepareFlag) (stmt *Stmt, tail string, err error) {
179-
if len(sql) > _MAX_LENGTH {
179+
if len(sql) > _MAX_SQL_LENGTH {
180180
return nil, "", TOOBIG
181181
}
182182

vfs/adiantum/hbsh.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,13 @@ func (h *hbshFile) SharedMemory() vfs.SharedMemory {
168168

169169
// Wrap optional methods.
170170

171+
func (h *hbshFile) ChunkSize(size int) {
172+
if f, ok := h.File.(vfs.FileChunkSize); ok {
173+
size = (size + blockSize - 1) &^ (blockSize - 1) // round up
174+
f.ChunkSize(size)
175+
}
176+
}
177+
171178
func (h *hbshFile) SizeHint(size int64) error {
172179
if f, ok := h.File.(vfs.FileSizeHint); ok {
173180
size = (size + blockSize - 1) &^ (blockSize - 1) // round up
@@ -217,3 +224,17 @@ func (h *hbshFile) RollbackAtomicWrite() error {
217224
}
218225
return sqlite3.NOTFOUND
219226
}
227+
228+
func (h *hbshFile) CheckpointDone() error {
229+
if f, ok := h.File.(vfs.FileCheckpoint); ok {
230+
return f.CheckpointDone()
231+
}
232+
return sqlite3.NOTFOUND
233+
}
234+
235+
func (h *hbshFile) CheckpointStart() error {
236+
if f, ok := h.File.(vfs.FileCheckpoint); ok {
237+
return f.CheckpointStart()
238+
}
239+
return sqlite3.NOTFOUND
240+
}

vfs/api.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ type FileLockState interface {
5757
LockState() LockLevel
5858
}
5959

60+
// FileChunkSize extends File to implement the
61+
// SQLITE_FCNTL_CHUNK_SIZE file control opcode.
62+
//
63+
// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlchunksize
64+
type FileChunkSize interface {
65+
File
66+
ChunkSize(size int)
67+
}
68+
6069
// FileSizeHint extends File to implement the
6170
// SQLITE_FCNTL_SIZE_HINT file control opcode.
6271
//
@@ -125,6 +134,26 @@ type FileBatchAtomicWrite interface {
125134
RollbackAtomicWrite() error
126135
}
127136

137+
// FilePragma extends File to implement the
138+
// SQLITE_FCNTL_PRAGMA file control opcode.
139+
//
140+
// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlpragma
141+
type FilePragma interface {
142+
File
143+
Pragma(name, value string) (string, error)
144+
}
145+
146+
// FileCheckpoint extends File to implement the
147+
// SQLITE_FCNTL_CKPT_START and SQLITE_FCNTL_CKPT_DONE
148+
// file control opcodes.
149+
//
150+
// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlckptstart
151+
type FileCheckpoint interface {
152+
File
153+
CheckpointDone() error
154+
CheckpointStart() error
155+
}
156+
128157
// FileSharedMemory extends File to possibly implement shared memory.
129158
// It's OK for SharedMemory to return nil.
130159
type FileSharedMemory interface {

vfs/const.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ import "github.com/ncruces/go-sqlite3/internal/util"
44

55
const (
66
_MAX_NAME = 1e6 // Self-imposed limit for most NUL terminated strings.
7+
_MAX_SQL_LENGTH = 1e9
78
_MAX_PATHNAME = 1024
89
_DEFAULT_SECTOR_SIZE = 4096
10+
11+
ptrlen = 4
912
)
1013

1114
// https://sqlite.org/rescode.html
@@ -17,6 +20,7 @@ func (e _ErrorCode) Error() string {
1720

1821
const (
1922
_OK _ErrorCode = util.OK
23+
_ERROR _ErrorCode = util.ERROR
2024
_PERM _ErrorCode = util.PERM
2125
_BUSY _ErrorCode = util.BUSY
2226
_READONLY _ErrorCode = util.READONLY

vfs/vfs.go

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,13 @@ func vfsFileControl(ctx context.Context, mod api.Module, pFile uint32, op _Fcntl
284284
return _OK
285285
}
286286

287+
case _FCNTL_CHUNK_SIZE:
288+
if file, ok := file.(FileChunkSize); ok {
289+
size := util.ReadUint32(mod, pArg)
290+
file.ChunkSize(int(size))
291+
return _OK
292+
}
293+
287294
case _FCNTL_SIZE_HINT:
288295
if file, ok := file.(FileSizeHint); ok {
289296
size := util.ReadUint64(mod, pArg)
@@ -329,14 +336,45 @@ func vfsFileControl(ctx context.Context, mod api.Module, pFile uint32, op _Fcntl
329336
err := file.RollbackAtomicWrite()
330337
return vfsErrorCode(err, _IOERR_ROLLBACK_ATOMIC)
331338
}
339+
340+
case _FCNTL_CKPT_DONE:
341+
if file, ok := file.(FileCheckpoint); ok {
342+
err := file.CheckpointDone()
343+
return vfsErrorCode(err, _IOERR)
344+
}
345+
case _FCNTL_CKPT_START:
346+
if file, ok := file.(FileCheckpoint); ok {
347+
err := file.CheckpointStart()
348+
return vfsErrorCode(err, _IOERR)
349+
}
350+
351+
case _FCNTL_PRAGMA:
352+
if file, ok := file.(FilePragma); ok {
353+
name := util.ReadUint32(mod, pArg+1*ptrlen)
354+
value := util.ReadUint32(mod, pArg+2*ptrlen)
355+
out, err := file.Pragma(
356+
util.ReadString(mod, name, _MAX_SQL_LENGTH),
357+
util.ReadString(mod, value, _MAX_SQL_LENGTH))
358+
if err != nil {
359+
out = err.Error()
360+
}
361+
if out != "" {
362+
fn := mod.ExportedFunction("malloc")
363+
stack := [...]uint64{uint64(len(out) + 1)}
364+
if err := fn.CallWithStack(ctx, stack[:]); err != nil {
365+
panic(err)
366+
}
367+
util.WriteUint32(mod, pArg, uint32(stack[0]))
368+
util.WriteString(mod, uint32(stack[0]), out)
369+
return _ERROR
370+
}
371+
return vfsErrorCode(err, _ERROR)
372+
}
332373
}
333374

334375
// Consider also implementing these opcodes (in use by SQLite):
335376
// _FCNTL_BUSYHANDLER
336-
// _FCNTL_CHUNK_SIZE
337-
// _FCNTL_CKPT_DONE
338-
// _FCNTL_CKPT_START
339-
// _FCNTL_PRAGMA
377+
// _FCNTL_LAST_ERRNO
340378
// _FCNTL_SYNC
341379
return _NOTFOUND
342380
}

0 commit comments

Comments
 (0)