mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-12 05:59:14 +00:00
More VFS API.
This commit is contained in:
33
const.go
33
const.go
@@ -143,28 +143,17 @@ const (
|
||||
type OpenFlag uint32
|
||||
|
||||
const (
|
||||
OPEN_READONLY OpenFlag = 0x00000001 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_READWRITE OpenFlag = 0x00000002 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_CREATE OpenFlag = 0x00000004 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_DELETEONCLOSE OpenFlag = 0x00000008 /* VFS only */
|
||||
OPEN_EXCLUSIVE OpenFlag = 0x00000010 /* VFS only */
|
||||
OPEN_AUTOPROXY OpenFlag = 0x00000020 /* VFS only */
|
||||
OPEN_URI OpenFlag = 0x00000040 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_MEMORY OpenFlag = 0x00000080 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_MAIN_DB OpenFlag = 0x00000100 /* VFS only */
|
||||
OPEN_TEMP_DB OpenFlag = 0x00000200 /* VFS only */
|
||||
OPEN_TRANSIENT_DB OpenFlag = 0x00000400 /* VFS only */
|
||||
OPEN_MAIN_JOURNAL OpenFlag = 0x00000800 /* VFS only */
|
||||
OPEN_TEMP_JOURNAL OpenFlag = 0x00001000 /* VFS only */
|
||||
OPEN_SUBJOURNAL OpenFlag = 0x00002000 /* VFS only */
|
||||
OPEN_SUPER_JOURNAL OpenFlag = 0x00004000 /* VFS only */
|
||||
OPEN_NOMUTEX OpenFlag = 0x00008000 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_FULLMUTEX OpenFlag = 0x00010000 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_SHAREDCACHE OpenFlag = 0x00020000 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_PRIVATECACHE OpenFlag = 0x00040000 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_WAL OpenFlag = 0x00080000 /* VFS only */
|
||||
OPEN_NOFOLLOW OpenFlag = 0x01000000 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_EXRESCODE OpenFlag = 0x02000000 /* Extended result codes */
|
||||
OPEN_READONLY OpenFlag = 0x00000001 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_READWRITE OpenFlag = 0x00000002 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_CREATE OpenFlag = 0x00000004 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_URI OpenFlag = 0x00000040 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_MEMORY OpenFlag = 0x00000080 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_NOMUTEX OpenFlag = 0x00008000 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_FULLMUTEX OpenFlag = 0x00010000 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_SHAREDCACHE OpenFlag = 0x00020000 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_PRIVATECACHE OpenFlag = 0x00040000 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_NOFOLLOW OpenFlag = 0x01000000 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_EXRESCODE OpenFlag = 0x02000000 /* Extended result codes */
|
||||
)
|
||||
|
||||
// PrepareFlag is a flag that can be passed to [Conn.PrepareFlags].
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package vfs
|
||||
|
||||
import "github.com/ncruces/go-sqlite3/sqlite3vfs"
|
||||
|
||||
const (
|
||||
_MAX_STRING = 512 // Used for short strings: names, error messages…
|
||||
_MAX_PATHNAME = 512
|
||||
_DEFAULT_SECTOR_SIZE = 4096
|
||||
)
|
||||
@@ -59,93 +62,59 @@ const (
|
||||
)
|
||||
|
||||
// https://www.sqlite.org/c3ref/c_open_autoproxy.html
|
||||
type _OpenFlag uint32
|
||||
type _OpenFlag = sqlite3vfs.OpenFlag
|
||||
|
||||
const (
|
||||
_OPEN_READONLY _OpenFlag = 0x00000001 /* Ok for sqlite3_open_v2() */
|
||||
_OPEN_READWRITE _OpenFlag = 0x00000002 /* Ok for sqlite3_open_v2() */
|
||||
_OPEN_CREATE _OpenFlag = 0x00000004 /* Ok for sqlite3_open_v2() */
|
||||
_OPEN_DELETEONCLOSE _OpenFlag = 0x00000008 /* VFS only */
|
||||
_OPEN_EXCLUSIVE _OpenFlag = 0x00000010 /* VFS only */
|
||||
_OPEN_AUTOPROXY _OpenFlag = 0x00000020 /* VFS only */
|
||||
_OPEN_URI _OpenFlag = 0x00000040 /* Ok for sqlite3_open_v2() */
|
||||
_OPEN_MEMORY _OpenFlag = 0x00000080 /* Ok for sqlite3_open_v2() */
|
||||
_OPEN_MAIN_DB _OpenFlag = 0x00000100 /* VFS only */
|
||||
_OPEN_TEMP_DB _OpenFlag = 0x00000200 /* VFS only */
|
||||
_OPEN_TRANSIENT_DB _OpenFlag = 0x00000400 /* VFS only */
|
||||
_OPEN_MAIN_JOURNAL _OpenFlag = 0x00000800 /* VFS only */
|
||||
_OPEN_TEMP_JOURNAL _OpenFlag = 0x00001000 /* VFS only */
|
||||
_OPEN_SUBJOURNAL _OpenFlag = 0x00002000 /* VFS only */
|
||||
_OPEN_SUPER_JOURNAL _OpenFlag = 0x00004000 /* VFS only */
|
||||
_OPEN_NOMUTEX _OpenFlag = 0x00008000 /* Ok for sqlite3_open_v2() */
|
||||
_OPEN_FULLMUTEX _OpenFlag = 0x00010000 /* Ok for sqlite3_open_v2() */
|
||||
_OPEN_SHAREDCACHE _OpenFlag = 0x00020000 /* Ok for sqlite3_open_v2() */
|
||||
_OPEN_PRIVATECACHE _OpenFlag = 0x00040000 /* Ok for sqlite3_open_v2() */
|
||||
_OPEN_WAL _OpenFlag = 0x00080000 /* VFS only */
|
||||
_OPEN_NOFOLLOW _OpenFlag = 0x01000000 /* Ok for sqlite3_open_v2() */
|
||||
_OPEN_EXRESCODE _OpenFlag = 0x02000000 /* Extended result codes */
|
||||
_OPEN_READONLY = sqlite3vfs.OPEN_READONLY
|
||||
_OPEN_READWRITE = sqlite3vfs.OPEN_READWRITE
|
||||
_OPEN_CREATE = sqlite3vfs.OPEN_CREATE
|
||||
_OPEN_DELETEONCLOSE = sqlite3vfs.OPEN_DELETEONCLOSE
|
||||
_OPEN_EXCLUSIVE = sqlite3vfs.OPEN_EXCLUSIVE
|
||||
_OPEN_AUTOPROXY = sqlite3vfs.OPEN_AUTOPROXY
|
||||
_OPEN_URI = sqlite3vfs.OPEN_URI
|
||||
_OPEN_MEMORY = sqlite3vfs.OPEN_MEMORY
|
||||
_OPEN_MAIN_DB = sqlite3vfs.OPEN_MAIN_DB
|
||||
_OPEN_TEMP_DB = sqlite3vfs.OPEN_TEMP_DB
|
||||
_OPEN_TRANSIENT_DB = sqlite3vfs.OPEN_TRANSIENT_DB
|
||||
_OPEN_MAIN_JOURNAL = sqlite3vfs.OPEN_MAIN_JOURNAL
|
||||
_OPEN_TEMP_JOURNAL = sqlite3vfs.OPEN_TEMP_JOURNAL
|
||||
_OPEN_SUBJOURNAL = sqlite3vfs.OPEN_SUBJOURNAL
|
||||
_OPEN_SUPER_JOURNAL = sqlite3vfs.OPEN_SUPER_JOURNAL
|
||||
_OPEN_NOMUTEX = sqlite3vfs.OPEN_NOMUTEX
|
||||
_OPEN_FULLMUTEX = sqlite3vfs.OPEN_FULLMUTEX
|
||||
_OPEN_SHAREDCACHE = sqlite3vfs.OPEN_SHAREDCACHE
|
||||
_OPEN_PRIVATECACHE = sqlite3vfs.OPEN_PRIVATECACHE
|
||||
_OPEN_WAL = sqlite3vfs.OPEN_WAL
|
||||
_OPEN_NOFOLLOW = sqlite3vfs.OPEN_NOFOLLOW
|
||||
)
|
||||
|
||||
// https://www.sqlite.org/c3ref/c_access_exists.html
|
||||
type _AccessFlag uint32
|
||||
type _AccessFlag = sqlite3vfs.AccessFlag
|
||||
|
||||
const (
|
||||
_ACCESS_EXISTS _AccessFlag = 0
|
||||
_ACCESS_READWRITE _AccessFlag = 1 /* Used by PRAGMA temp_store_directory */
|
||||
_ACCESS_READ _AccessFlag = 2 /* Unused */
|
||||
_ACCESS_EXISTS = sqlite3vfs.ACCESS_EXISTS
|
||||
_ACCESS_READWRITE = sqlite3vfs.ACCESS_READWRITE
|
||||
_ACCESS_READ = sqlite3vfs.ACCESS_READ
|
||||
)
|
||||
|
||||
// https://www.sqlite.org/c3ref/c_sync_dataonly.html
|
||||
type _SyncFlag uint32
|
||||
type _SyncFlag = sqlite3vfs.SyncFlag
|
||||
|
||||
const (
|
||||
_SYNC_NORMAL _SyncFlag = 0x00002
|
||||
_SYNC_FULL _SyncFlag = 0x00003
|
||||
_SYNC_DATAONLY _SyncFlag = 0x00010
|
||||
_SYNC_NORMAL = sqlite3vfs.SYNC_NORMAL
|
||||
_SYNC_FULL = sqlite3vfs.SYNC_FULL
|
||||
_SYNC_DATAONLY = sqlite3vfs.SYNC_DATAONLY
|
||||
)
|
||||
|
||||
// https://www.sqlite.org/c3ref/c_lock_exclusive.html
|
||||
type _LockLevel uint32
|
||||
type _LockLevel = sqlite3vfs.LockLevel
|
||||
|
||||
const (
|
||||
// No locks are held on the database.
|
||||
// The database may be neither read nor written.
|
||||
// Any internally cached data is considered suspect and subject to
|
||||
// verification against the database file before being used.
|
||||
// Other processes can read or write the database as their own locking
|
||||
// states permit.
|
||||
// This is the default state.
|
||||
_LOCK_NONE _LockLevel = 0 /* xUnlock() only */
|
||||
|
||||
// The database may be read but not written.
|
||||
// Any number of processes can hold SHARED locks at the same time,
|
||||
// hence there can be many simultaneous readers.
|
||||
// But no other thread or process is allowed to write to the database file
|
||||
// while one or more SHARED locks are active.
|
||||
_LOCK_SHARED _LockLevel = 1 /* xLock() or xUnlock() */
|
||||
|
||||
// A RESERVED lock means that the process is planning on writing to the
|
||||
// database file at some point in the future but that it is currently just
|
||||
// reading from the file.
|
||||
// Only a single RESERVED lock may be active at one time,
|
||||
// though multiple SHARED locks can coexist with a single RESERVED lock.
|
||||
// RESERVED differs from PENDING in that new SHARED locks can be acquired
|
||||
// while there is a RESERVED lock.
|
||||
_LOCK_RESERVED _LockLevel = 2 /* xLock() only */
|
||||
|
||||
// A PENDING lock means that the process holding the lock wants to write to
|
||||
// the database as soon as possible and is just waiting on all current
|
||||
// SHARED locks to clear so that it can get an EXCLUSIVE lock.
|
||||
// No new SHARED locks are permitted against the database if a PENDING lock
|
||||
// is active, though existing SHARED locks are allowed to continue.
|
||||
_LOCK_PENDING _LockLevel = 3 /* internal use only */
|
||||
|
||||
// An EXCLUSIVE lock is needed in order to write to the database file.
|
||||
// Only one EXCLUSIVE lock is allowed on the file and no other locks of any
|
||||
// kind are allowed to coexist with an EXCLUSIVE lock.
|
||||
// In order to maximize concurrency, SQLite works to minimize the amount of
|
||||
// time that EXCLUSIVE locks are held.
|
||||
_LOCK_EXCLUSIVE _LockLevel = 4 /* xLock() only */
|
||||
_LOCK_NONE = sqlite3vfs.LOCK_NONE
|
||||
_LOCK_SHARED = sqlite3vfs.LOCK_SHARED
|
||||
_LOCK_RESERVED = sqlite3vfs.LOCK_RESERVED
|
||||
_LOCK_PENDING = sqlite3vfs.LOCK_PENDING
|
||||
_LOCK_EXCLUSIVE = sqlite3vfs.LOCK_EXCLUSIVE
|
||||
)
|
||||
|
||||
// https://www.sqlite.org/c3ref/c_fcntl_begin_atomic_write.html
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ncruces/go-sqlite3/internal/util"
|
||||
"github.com/ncruces/go-sqlite3/sqlite3vfs"
|
||||
"github.com/ncruces/julianday"
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
@@ -64,6 +65,10 @@ func (vfs *vfsState) Close() error {
|
||||
}
|
||||
|
||||
func vfsFind(ctx context.Context, mod api.Module, zVfsName uint32) uint32 {
|
||||
name := util.ReadString(mod, zVfsName, _MAX_STRING)
|
||||
if sqlite3vfs.Find(name) != nil {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -113,10 +118,29 @@ func vfsCurrentTime64(ctx context.Context, mod api.Module, pVfs, piNow uint32) _
|
||||
}
|
||||
|
||||
func vfsFullPathname(ctx context.Context, mod api.Module, pVfs, zRelative, nFull, zFull uint32) _ErrorCode {
|
||||
vfs := getVFS(mod, pVfs)
|
||||
rel := util.ReadString(mod, zRelative, _MAX_PATHNAME)
|
||||
abs, err := filepath.Abs(rel)
|
||||
if err != nil {
|
||||
return _CANTOPEN_FULLPATH
|
||||
|
||||
var abs string
|
||||
var symlink bool
|
||||
if vfs != nil {
|
||||
p, err := vfs.FullPathname(rel)
|
||||
if err != nil {
|
||||
return _CANTOPEN_FULLPATH
|
||||
}
|
||||
abs = p
|
||||
} else {
|
||||
p, err := filepath.Abs(rel)
|
||||
if err != nil {
|
||||
return _CANTOPEN_FULLPATH
|
||||
}
|
||||
s, err := os.Lstat(p)
|
||||
if err == nil {
|
||||
symlink = s.Mode()&fs.ModeSymlink != 0
|
||||
} else if !errors.Is(err, fs.ErrNotExist) {
|
||||
return _CANTOPEN_FULLPATH
|
||||
}
|
||||
abs = p
|
||||
}
|
||||
|
||||
size := uint64(len(abs) + 1)
|
||||
@@ -127,15 +151,10 @@ func vfsFullPathname(ctx context.Context, mod api.Module, pVfs, zRelative, nFull
|
||||
mem[len(abs)] = 0
|
||||
copy(mem, abs)
|
||||
|
||||
if fi, err := os.Lstat(abs); err == nil {
|
||||
if fi.Mode()&fs.ModeSymlink != 0 {
|
||||
return _OK_SYMLINK
|
||||
}
|
||||
return _OK
|
||||
} else if errors.Is(err, fs.ErrNotExist) {
|
||||
return _OK
|
||||
if symlink {
|
||||
return _OK_SYMLINK
|
||||
}
|
||||
return _CANTOPEN_FULLPATH
|
||||
return _OK
|
||||
}
|
||||
|
||||
func vfsDelete(ctx context.Context, mod api.Module, pVfs, zPath, syncDir uint32) _ErrorCode {
|
||||
@@ -192,6 +211,8 @@ func vfsAccess(ctx context.Context, mod api.Module, pVfs, zPath uint32, flags _A
|
||||
}
|
||||
|
||||
func vfsOpen(ctx context.Context, mod api.Module, pVfs, zName, pFile uint32, flags _OpenFlag, pOutFlags uint32) _ErrorCode {
|
||||
vfs := getVFS(mod, pVfs)
|
||||
|
||||
var oflags int
|
||||
if flags&_OPEN_EXCLUSIVE != 0 {
|
||||
oflags |= os.O_EXCL
|
||||
@@ -207,11 +228,17 @@ func vfsOpen(ctx context.Context, mod api.Module, pVfs, zName, pFile uint32, fla
|
||||
}
|
||||
|
||||
var err error
|
||||
var name string
|
||||
var f *os.File
|
||||
if zName == 0 {
|
||||
if zName != 0 {
|
||||
name = util.ReadString(mod, zName, _MAX_PATHNAME)
|
||||
}
|
||||
switch {
|
||||
case vfs != nil:
|
||||
_, flags, err = vfs.Open(name, flags)
|
||||
case name == "":
|
||||
f, err = os.CreateTemp("", "*.db")
|
||||
} else {
|
||||
name := util.ReadString(mod, zName, _MAX_PATHNAME)
|
||||
default:
|
||||
f, err = osOpenFile(name, oflags, 0666)
|
||||
}
|
||||
if err != nil {
|
||||
@@ -393,3 +420,11 @@ func vfsFileMoved(ctx context.Context, mod api.Module, pFile, pResOut uint32) _E
|
||||
util.WriteUint32(mod, pResOut, res)
|
||||
return _OK
|
||||
}
|
||||
|
||||
func getVFS(mod api.Module, pVfs uint32) sqlite3vfs.VFS {
|
||||
if pVfs == 0 {
|
||||
return nil
|
||||
}
|
||||
name := util.ReadString(mod, util.ReadUint32(mod, pVfs+16), _MAX_STRING)
|
||||
return sqlite3vfs.Find(name)
|
||||
}
|
||||
|
||||
98
sqlite3vfs/const.go
Normal file
98
sqlite3vfs/const.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package sqlite3vfs
|
||||
|
||||
// OpenFlag is a flag for the [VFS.Open] method.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/c_open_autoproxy.html
|
||||
type OpenFlag uint32
|
||||
|
||||
const (
|
||||
OPEN_READONLY OpenFlag = 0x00000001 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_READWRITE OpenFlag = 0x00000002 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_CREATE OpenFlag = 0x00000004 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_DELETEONCLOSE OpenFlag = 0x00000008 /* VFS only */
|
||||
OPEN_EXCLUSIVE OpenFlag = 0x00000010 /* VFS only */
|
||||
OPEN_AUTOPROXY OpenFlag = 0x00000020 /* VFS only */
|
||||
OPEN_URI OpenFlag = 0x00000040 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_MEMORY OpenFlag = 0x00000080 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_MAIN_DB OpenFlag = 0x00000100 /* VFS only */
|
||||
OPEN_TEMP_DB OpenFlag = 0x00000200 /* VFS only */
|
||||
OPEN_TRANSIENT_DB OpenFlag = 0x00000400 /* VFS only */
|
||||
OPEN_MAIN_JOURNAL OpenFlag = 0x00000800 /* VFS only */
|
||||
OPEN_TEMP_JOURNAL OpenFlag = 0x00001000 /* VFS only */
|
||||
OPEN_SUBJOURNAL OpenFlag = 0x00002000 /* VFS only */
|
||||
OPEN_SUPER_JOURNAL OpenFlag = 0x00004000 /* VFS only */
|
||||
OPEN_NOMUTEX OpenFlag = 0x00008000 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_FULLMUTEX OpenFlag = 0x00010000 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_SHAREDCACHE OpenFlag = 0x00020000 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_PRIVATECACHE OpenFlag = 0x00040000 /* Ok for sqlite3_open_v2() */
|
||||
OPEN_WAL OpenFlag = 0x00080000 /* VFS only */
|
||||
OPEN_NOFOLLOW OpenFlag = 0x01000000 /* Ok for sqlite3_open_v2() */
|
||||
)
|
||||
|
||||
// AccessFlag is a flag for the [VFS.Access] method.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/c_access_exists.html
|
||||
type AccessFlag uint32
|
||||
|
||||
const (
|
||||
ACCESS_EXISTS AccessFlag = 0
|
||||
ACCESS_READWRITE AccessFlag = 1 /* Used by PRAGMA temp_store_directory */
|
||||
ACCESS_READ AccessFlag = 2 /* Unused */
|
||||
)
|
||||
|
||||
// SyncFlag is a flag for the [File.Sync] method.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/c_sync_dataonly.html
|
||||
type SyncFlag uint32
|
||||
|
||||
const (
|
||||
SYNC_NORMAL SyncFlag = 0x00002
|
||||
SYNC_FULL SyncFlag = 0x00003
|
||||
SYNC_DATAONLY SyncFlag = 0x00010
|
||||
)
|
||||
|
||||
// LockLevel is a value used with [File.Lock] and [File.Unlock] methods.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/c_lock_exclusive.html
|
||||
type LockLevel uint32
|
||||
|
||||
const (
|
||||
// No locks are held on the database.
|
||||
// The database may be neither read nor written.
|
||||
// Any internally cached data is considered suspect and subject to
|
||||
// verification against the database file before being used.
|
||||
// Other processes can read or write the database as their own locking
|
||||
// states permit.
|
||||
// This is the default state.
|
||||
LOCK_NONE LockLevel = 0 /* xUnlock() only */
|
||||
|
||||
// The database may be read but not written.
|
||||
// Any number of processes can hold SHARED locks at the same time,
|
||||
// hence there can be many simultaneous readers.
|
||||
// But no other thread or process is allowed to write to the database file
|
||||
// while one or more SHARED locks are active.
|
||||
LOCK_SHARED LockLevel = 1 /* xLock() or xUnlock() */
|
||||
|
||||
// A RESERVED lock means that the process is planning on writing to the
|
||||
// database file at some point in the future but that it is currently just
|
||||
// reading from the file.
|
||||
// Only a single RESERVED lock may be active at one time,
|
||||
// though multiple SHARED locks can coexist with a single RESERVED lock.
|
||||
// RESERVED differs from PENDING in that new SHARED locks can be acquired
|
||||
// while there is a RESERVED lock.
|
||||
LOCK_RESERVED LockLevel = 2 /* xLock() only */
|
||||
|
||||
// A PENDING lock means that the process holding the lock wants to write to
|
||||
// the database as soon as possible and is just waiting on all current
|
||||
// SHARED locks to clear so that it can get an EXCLUSIVE lock.
|
||||
// No new SHARED locks are permitted against the database if a PENDING lock
|
||||
// is active, though existing SHARED locks are allowed to continue.
|
||||
LOCK_PENDING LockLevel = 3 /* internal use only */
|
||||
|
||||
// An EXCLUSIVE lock is needed in order to write to the database file.
|
||||
// Only one EXCLUSIVE lock is allowed on the file and no other locks of any
|
||||
// kind are allowed to coexist with an EXCLUSIVE lock.
|
||||
// In order to maximize concurrency, SQLite works to minimize the amount of
|
||||
// time that EXCLUSIVE locks are held.
|
||||
LOCK_EXCLUSIVE LockLevel = 4 /* xLock() only */
|
||||
)
|
||||
49
sqlite3vfs/vfs.go
Normal file
49
sqlite3vfs/vfs.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package sqlite3vfs
|
||||
|
||||
import "sync"
|
||||
|
||||
type VFS interface {
|
||||
Open(name string, flags OpenFlag) (File, OpenFlag, error)
|
||||
Delete(name string, dirSync bool) error
|
||||
Access(name string, flags AccessFlag) (bool, error)
|
||||
FullPathname(name string) (string, error)
|
||||
}
|
||||
|
||||
type File interface {
|
||||
Close() error
|
||||
ReadAt(p []byte, off int64) (n int, err error)
|
||||
WriteAt(p []byte, off int64) (n int, err error)
|
||||
Truncate(size int64) error
|
||||
Sync(flag SyncFlag) error
|
||||
FileSize() (int64, error)
|
||||
Lock(elock LockLevel) error
|
||||
Unlock(elock LockLevel) error
|
||||
CheckReservedLock() (bool, error)
|
||||
SectorSize() int64
|
||||
}
|
||||
|
||||
var (
|
||||
vfsRegistry map[string]VFS
|
||||
vfsRegistryMtx sync.Mutex
|
||||
)
|
||||
|
||||
func Find(name string) VFS {
|
||||
vfsRegistryMtx.Lock()
|
||||
defer vfsRegistryMtx.Unlock()
|
||||
return vfsRegistry[name]
|
||||
}
|
||||
|
||||
func Register(name string, vfs VFS) {
|
||||
vfsRegistryMtx.Lock()
|
||||
defer vfsRegistryMtx.Unlock()
|
||||
if vfsRegistry == nil {
|
||||
vfsRegistry = map[string]VFS{}
|
||||
}
|
||||
vfsRegistry[name] = vfs
|
||||
}
|
||||
|
||||
func Unregister(name string) {
|
||||
vfsRegistryMtx.Lock()
|
||||
defer vfsRegistryMtx.Unlock()
|
||||
delete(vfsRegistry, name)
|
||||
}
|
||||
46
sqlite3vfs/vfs_api_test.go
Normal file
46
sqlite3vfs/vfs_api_test.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package sqlite3vfs_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/ncruces/go-sqlite3"
|
||||
_ "github.com/ncruces/go-sqlite3/embed"
|
||||
"github.com/ncruces/go-sqlite3/sqlite3vfs"
|
||||
)
|
||||
|
||||
type testVFS struct {
|
||||
*testing.T
|
||||
}
|
||||
|
||||
func (t testVFS) Open(name string, flags sqlite3vfs.OpenFlag) (sqlite3vfs.File, sqlite3vfs.OpenFlag, error) {
|
||||
t.Log("Open", name, flags)
|
||||
t.SkipNow()
|
||||
return nil, flags, nil
|
||||
}
|
||||
|
||||
func (testVFS) Delete(name string, dirSync bool) error {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
func (testVFS) Access(name string, flags sqlite3vfs.AccessFlag) (bool, error) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
func (t testVFS) FullPathname(name string) (string, error) {
|
||||
t.Log("FullPathname", name)
|
||||
return name, nil
|
||||
}
|
||||
|
||||
func TestRegister(t *testing.T) {
|
||||
vfs := testVFS{t}
|
||||
sqlite3vfs.Register("foo", vfs)
|
||||
defer sqlite3vfs.Unregister("foo")
|
||||
|
||||
defer func() { _ = recover() }()
|
||||
|
||||
conn, err := sqlite3.Open("file:file.db?vfs=foo")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
}
|
||||
Reference in New Issue
Block a user