mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-11 21:49:13 +00:00
VFS pragma.
This commit is contained in:
@@ -89,7 +89,6 @@ It also benefits greatly from [SQLite's](https://sqlite.org/testing.html) and
|
||||
|
||||
Every commit is [tested](.github/workflows/test.yml) on
|
||||
Linux (amd64/arm64/386/riscv64), macOS (amd64/arm64), Windows, FreeBSD and illumos.
|
||||
|
||||
The Go VFS is tested by running SQLite's
|
||||
[mptest](https://github.com/sqlite/sqlite/blob/master/mptest/mptest.c).
|
||||
|
||||
|
||||
2
conn.go
2
conn.go
@@ -176,7 +176,7 @@ func (c *Conn) Prepare(sql string) (stmt *Stmt, tail string, err error) {
|
||||
//
|
||||
// https://sqlite.org/c3ref/prepare.html
|
||||
func (c *Conn) PrepareFlags(sql string, flags PrepareFlag) (stmt *Stmt, tail string, err error) {
|
||||
if len(sql) > _MAX_LENGTH {
|
||||
if len(sql) > _MAX_SQL_LENGTH {
|
||||
return nil, "", TOOBIG
|
||||
}
|
||||
|
||||
|
||||
@@ -168,6 +168,13 @@ func (h *hbshFile) SharedMemory() vfs.SharedMemory {
|
||||
|
||||
// Wrap optional methods.
|
||||
|
||||
func (h *hbshFile) ChunkSize(size int) {
|
||||
if f, ok := h.File.(vfs.FileChunkSize); ok {
|
||||
size = (size + blockSize - 1) &^ (blockSize - 1) // round up
|
||||
f.ChunkSize(size)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *hbshFile) SizeHint(size int64) error {
|
||||
if f, ok := h.File.(vfs.FileSizeHint); ok {
|
||||
size = (size + blockSize - 1) &^ (blockSize - 1) // round up
|
||||
@@ -217,3 +224,17 @@ func (h *hbshFile) RollbackAtomicWrite() error {
|
||||
}
|
||||
return sqlite3.NOTFOUND
|
||||
}
|
||||
|
||||
func (h *hbshFile) CheckpointDone() error {
|
||||
if f, ok := h.File.(vfs.FileCheckpoint); ok {
|
||||
return f.CheckpointDone()
|
||||
}
|
||||
return sqlite3.NOTFOUND
|
||||
}
|
||||
|
||||
func (h *hbshFile) CheckpointStart() error {
|
||||
if f, ok := h.File.(vfs.FileCheckpoint); ok {
|
||||
return f.CheckpointStart()
|
||||
}
|
||||
return sqlite3.NOTFOUND
|
||||
}
|
||||
|
||||
29
vfs/api.go
29
vfs/api.go
@@ -57,6 +57,15 @@ type FileLockState interface {
|
||||
LockState() LockLevel
|
||||
}
|
||||
|
||||
// FileChunkSize extends File to implement the
|
||||
// SQLITE_FCNTL_CHUNK_SIZE file control opcode.
|
||||
//
|
||||
// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlchunksize
|
||||
type FileChunkSize interface {
|
||||
File
|
||||
ChunkSize(size int)
|
||||
}
|
||||
|
||||
// FileSizeHint extends File to implement the
|
||||
// SQLITE_FCNTL_SIZE_HINT file control opcode.
|
||||
//
|
||||
@@ -125,6 +134,26 @@ type FileBatchAtomicWrite interface {
|
||||
RollbackAtomicWrite() error
|
||||
}
|
||||
|
||||
// FilePragma extends File to implement the
|
||||
// SQLITE_FCNTL_PRAGMA file control opcode.
|
||||
//
|
||||
// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlpragma
|
||||
type FilePragma interface {
|
||||
File
|
||||
Pragma(name, value string) (string, error)
|
||||
}
|
||||
|
||||
// FileCheckpoint extends File to implement the
|
||||
// SQLITE_FCNTL_CKPT_START and SQLITE_FCNTL_CKPT_DONE
|
||||
// file control opcodes.
|
||||
//
|
||||
// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlckptstart
|
||||
type FileCheckpoint interface {
|
||||
File
|
||||
CheckpointDone() error
|
||||
CheckpointStart() error
|
||||
}
|
||||
|
||||
// FileSharedMemory extends File to possibly implement shared memory.
|
||||
// It's OK for SharedMemory to return nil.
|
||||
type FileSharedMemory interface {
|
||||
|
||||
@@ -4,8 +4,11 @@ import "github.com/ncruces/go-sqlite3/internal/util"
|
||||
|
||||
const (
|
||||
_MAX_NAME = 1e6 // Self-imposed limit for most NUL terminated strings.
|
||||
_MAX_SQL_LENGTH = 1e9
|
||||
_MAX_PATHNAME = 1024
|
||||
_DEFAULT_SECTOR_SIZE = 4096
|
||||
|
||||
ptrlen = 4
|
||||
)
|
||||
|
||||
// https://sqlite.org/rescode.html
|
||||
@@ -17,6 +20,7 @@ func (e _ErrorCode) Error() string {
|
||||
|
||||
const (
|
||||
_OK _ErrorCode = util.OK
|
||||
_ERROR _ErrorCode = util.ERROR
|
||||
_PERM _ErrorCode = util.PERM
|
||||
_BUSY _ErrorCode = util.BUSY
|
||||
_READONLY _ErrorCode = util.READONLY
|
||||
|
||||
46
vfs/vfs.go
46
vfs/vfs.go
@@ -284,6 +284,13 @@ func vfsFileControl(ctx context.Context, mod api.Module, pFile uint32, op _Fcntl
|
||||
return _OK
|
||||
}
|
||||
|
||||
case _FCNTL_CHUNK_SIZE:
|
||||
if file, ok := file.(FileChunkSize); ok {
|
||||
size := util.ReadUint32(mod, pArg)
|
||||
file.ChunkSize(int(size))
|
||||
return _OK
|
||||
}
|
||||
|
||||
case _FCNTL_SIZE_HINT:
|
||||
if file, ok := file.(FileSizeHint); ok {
|
||||
size := util.ReadUint64(mod, pArg)
|
||||
@@ -329,14 +336,45 @@ func vfsFileControl(ctx context.Context, mod api.Module, pFile uint32, op _Fcntl
|
||||
err := file.RollbackAtomicWrite()
|
||||
return vfsErrorCode(err, _IOERR_ROLLBACK_ATOMIC)
|
||||
}
|
||||
|
||||
case _FCNTL_CKPT_DONE:
|
||||
if file, ok := file.(FileCheckpoint); ok {
|
||||
err := file.CheckpointDone()
|
||||
return vfsErrorCode(err, _IOERR)
|
||||
}
|
||||
case _FCNTL_CKPT_START:
|
||||
if file, ok := file.(FileCheckpoint); ok {
|
||||
err := file.CheckpointStart()
|
||||
return vfsErrorCode(err, _IOERR)
|
||||
}
|
||||
|
||||
case _FCNTL_PRAGMA:
|
||||
if file, ok := file.(FilePragma); ok {
|
||||
name := util.ReadUint32(mod, pArg+1*ptrlen)
|
||||
value := util.ReadUint32(mod, pArg+2*ptrlen)
|
||||
out, err := file.Pragma(
|
||||
util.ReadString(mod, name, _MAX_SQL_LENGTH),
|
||||
util.ReadString(mod, value, _MAX_SQL_LENGTH))
|
||||
if err != nil {
|
||||
out = err.Error()
|
||||
}
|
||||
if out != "" {
|
||||
fn := mod.ExportedFunction("malloc")
|
||||
stack := [...]uint64{uint64(len(out) + 1)}
|
||||
if err := fn.CallWithStack(ctx, stack[:]); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
util.WriteUint32(mod, pArg, uint32(stack[0]))
|
||||
util.WriteString(mod, uint32(stack[0]), out)
|
||||
return _ERROR
|
||||
}
|
||||
return vfsErrorCode(err, _ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
// Consider also implementing these opcodes (in use by SQLite):
|
||||
// _FCNTL_BUSYHANDLER
|
||||
// _FCNTL_CHUNK_SIZE
|
||||
// _FCNTL_CKPT_DONE
|
||||
// _FCNTL_CKPT_START
|
||||
// _FCNTL_PRAGMA
|
||||
// _FCNTL_LAST_ERRNO
|
||||
// _FCNTL_SYNC
|
||||
return _NOTFOUND
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user