VFS error handling.

This commit is contained in:
Nuno Cruces
2025-10-15 16:22:36 +01:00
parent 9e1cbfb5bb
commit 1db4366226
21 changed files with 209 additions and 130 deletions

View File

@@ -265,7 +265,7 @@ func traceCallback(ctx context.Context, mod api.Module, evt TraceEvent, pDB, pAr
} }
} }
if arg1 != nil { if arg1 != nil {
_, rc = errorCode(c.trace(evt, arg1, arg2), ERROR) _ = c.trace(evt, arg1, arg2)
} }
} }
return rc return rc

View File

@@ -198,14 +198,14 @@ func (ctx Context) ResultError(err error) {
return return
} }
msg, code := errorCode(err, _OK) msg, code := errorCode(err, ERROR)
if msg != "" { if msg != "" {
defer ctx.c.arena.mark()() defer ctx.c.arena.mark()()
ptr := ctx.c.arena.string(msg) ptr := ctx.c.arena.string(msg)
ctx.c.call("sqlite3_result_error", ctx.c.call("sqlite3_result_error",
stk_t(ctx.handle), stk_t(ptr), stk_t(len(msg))) stk_t(ctx.handle), stk_t(ptr), stk_t(len(msg)))
} }
if code != _OK { if code != res_t(ERROR) {
ctx.c.call("sqlite3_result_error_code", ctx.c.call("sqlite3_result_error_code",
stk_t(ctx.handle), stk_t(code)) stk_t(ctx.handle), stk_t(code))
} }

View File

@@ -44,8 +44,8 @@ func Test_Open_dir(t *testing.T) {
if err == nil { if err == nil {
t.Fatal("want error") t.Fatal("want error")
} }
if !errors.Is(err, sqlite3.CANTOPEN) { if !errors.Is(err, sqlite3.CANTOPEN_ISDIR) {
t.Errorf("got %v, want sqlite3.CANTOPEN", err) t.Errorf("got %v, want sqlite3.CANTOPEN_ISDIR", err)
} }
} }

View File

@@ -11,6 +11,7 @@ import (
// //
// https://sqlite.org/c3ref/errcode.html // https://sqlite.org/c3ref/errcode.html
type Error struct { type Error struct {
sys error
msg string msg string
sql string sql string
code res_t code res_t
@@ -33,7 +34,7 @@ func (e *Error) ExtendedCode() ExtendedErrorCode {
// Error implements the error interface. // Error implements the error interface.
func (e *Error) Error() string { func (e *Error) Error() string {
var b strings.Builder var b strings.Builder
b.WriteString(util.ErrorCodeString(uint32(e.code))) b.WriteString(util.ErrorCodeString(e.code))
if e.msg != "" { if e.msg != "" {
b.WriteString(": ") b.WriteString(": ")
@@ -43,6 +44,14 @@ func (e *Error) Error() string {
return b.String() return b.String()
} }
// Unwrap returns the underlying operating system error
// that caused the I/O error or failure to open a file.
//
// https://sqlite.org/c3ref/system_errno.html
func (e *Error) Unwrap() error {
return e.sys
}
// Is tests whether this error matches a given [ErrorCode] or [ExtendedErrorCode]. // Is tests whether this error matches a given [ErrorCode] or [ExtendedErrorCode].
// //
// It makes it possible to do: // It makes it possible to do:
@@ -90,7 +99,16 @@ func (e *Error) SQL() string {
// Error implements the error interface. // Error implements the error interface.
func (e ErrorCode) Error() string { func (e ErrorCode) Error() string {
return util.ErrorCodeString(uint32(e)) return util.ErrorCodeString(e)
}
// As converts this error to an [ExtendedErrorCode].
func (e ErrorCode) As(err any) bool {
c, ok := err.(*xErrorCode)
if ok {
*c = xErrorCode(e)
}
return ok
} }
// Temporary returns true for [BUSY] errors. // Temporary returns true for [BUSY] errors.
@@ -105,7 +123,7 @@ func (e ErrorCode) ExtendedCode() ExtendedErrorCode {
// Error implements the error interface. // Error implements the error interface.
func (e ExtendedErrorCode) Error() string { func (e ExtendedErrorCode) Error() string {
return util.ErrorCodeString(uint32(e)) return util.ErrorCodeString(e)
} }
// Is tests whether this error matches a given [ErrorCode]. // Is tests whether this error matches a given [ErrorCode].
@@ -150,14 +168,10 @@ func errorCode(err error, def ErrorCode) (msg string, code res_t) {
return code.msg, res_t(code.code) return code.msg, res_t(code.code)
} }
var ecode ErrorCode
var xcode xErrorCode var xcode xErrorCode
switch { if errors.As(err, &xcode) {
case errors.As(err, &xcode):
code = res_t(xcode) code = res_t(xcode)
case errors.As(err, &ecode): } else {
code = res_t(ecode)
default:
code = res_t(def) code = res_t(def)
} }
return err.Error(), code return err.Error(), code

View File

@@ -33,8 +33,12 @@ func AssertErr() ErrorString {
return ErrorString(msg) return ErrorString(msg)
} }
func ErrorCodeString(rc uint32) string { type errorCode interface {
switch rc { ~uint8 | ~uint16 | ~uint32 | ~int32
}
func ErrorCodeString[T errorCode](rc T) string {
switch uint32(rc) {
case ABORT_ROLLBACK: case ABORT_ROLLBACK:
return "sqlite3: abort due to ROLLBACK" return "sqlite3: abort due to ROLLBACK"
case ROW: case ROW:
@@ -42,7 +46,7 @@ func ErrorCodeString(rc uint32) string {
case DONE: case DONE:
return "sqlite3: no more rows available" return "sqlite3: no more rows available"
} }
switch rc & 0xff { switch uint8(rc) {
case OK: case OK:
return "sqlite3: not an error" return "sqlite3: not an error"
case ERROR: case ERROR:

View File

@@ -12,6 +12,7 @@ type ConnKey struct{}
type moduleKey struct{} type moduleKey struct{}
type moduleState struct { type moduleState struct {
sysError error
mmapState mmapState
handleState handleState
} }
@@ -23,3 +24,15 @@ func NewContext(ctx context.Context) context.Context {
ctx = context.WithValue(ctx, moduleKey{}, state) ctx = context.WithValue(ctx, moduleKey{}, state)
return ctx return ctx
} }
func GetSystemError(ctx context.Context) error {
s := ctx.Value(moduleKey{}).(*moduleState)
return s.sysError
}
func SetSystemError(ctx context.Context, err error) {
s, ok := ctx.Value(moduleKey{}).(*moduleState)
if ok {
s.sysError = err
}
}

View File

@@ -125,14 +125,15 @@ func (sqlt *sqlite) error(rc res_t, handle ptr_t, sql ...string) error {
panic(util.OOMErr) panic(util.OOMErr)
} }
if handle != 0 {
var msg, query string var msg, query string
if handle != 0 {
if ptr := ptr_t(sqlt.call("sqlite3_errmsg", stk_t(handle))); ptr != 0 { if ptr := ptr_t(sqlt.call("sqlite3_errmsg", stk_t(handle))); ptr != 0 {
msg = util.ReadString(sqlt.mod, ptr, _MAX_LENGTH) msg = util.ReadString(sqlt.mod, ptr, _MAX_LENGTH)
msg = strings.TrimPrefix(msg, "sqlite3: ")
msg = strings.TrimPrefix(msg, util.ErrorCodeString(rc)[len("sqlite3: "):])
msg = strings.TrimPrefix(msg, ": ")
if msg == "not an error" { if msg == "not an error" {
msg = "" msg = ""
} else {
msg = strings.TrimPrefix(msg, util.ErrorCodeString(uint32(rc))[len("sqlite3: "):])
} }
} }
@@ -141,10 +142,16 @@ func (sqlt *sqlite) error(rc res_t, handle ptr_t, sql ...string) error {
query = sql[0][i:] query = sql[0][i:]
} }
} }
if msg != "" || query != "" {
return &Error{code: rc, msg: msg, sql: query}
} }
var sys error
switch ErrorCode(rc) {
case CANTOPEN, IOERR:
sys = util.GetSystemError(sqlt.ctx)
}
if sys != nil || msg != "" || query != "" {
return &Error{code: rc, sys: sys, msg: msg, sql: query}
} }
return xErrorCode(rc) return xErrorCode(rc)
} }

View File

@@ -22,8 +22,8 @@ func TestConn_Open_dir(t *testing.T) {
if err == nil { if err == nil {
t.Fatal("want error") t.Fatal("want error")
} }
if !errors.Is(err, sqlite3.CANTOPEN) { if !errors.Is(err, sqlite3.CANTOPEN_ISDIR) {
t.Errorf("got %v, want sqlite3.CANTOPEN", err) t.Errorf("got %v, want sqlite3.CANTOPEN_ISDIR", err)
} }
} }

View File

@@ -73,7 +73,7 @@ to check if your build supports shared memory.
### Blocking Locks ### Blocking Locks
On Windows and macOS, this package implements On macOS, this package implements
[Wal-mode blocking locks](https://sqlite.org/src/doc/tip/doc/wal-lock.md). [Wal-mode blocking locks](https://sqlite.org/src/doc/tip/doc/wal-lock.md).
### Batch-Atomic Write ### Batch-Atomic Write

View File

@@ -193,8 +193,8 @@ type FileSharedMemory interface {
// SharedMemory is a shared-memory WAL-index implementation. // SharedMemory is a shared-memory WAL-index implementation.
// Use [NewSharedMemory] to create a shared-memory. // Use [NewSharedMemory] to create a shared-memory.
type SharedMemory interface { type SharedMemory interface {
shmMap(context.Context, api.Module, int32, int32, bool) (ptr_t, _ErrorCode) shmMap(context.Context, api.Module, int32, int32, bool) (ptr_t, error)
shmLock(int32, int32, _ShmFlag) _ErrorCode shmLock(int32, int32, _ShmFlag) error
shmUnmap(bool) shmUnmap(bool)
shmBarrier() shmBarrier()
io.Closer io.Closer

View File

@@ -20,7 +20,7 @@ type (
type _ErrorCode uint32 type _ErrorCode uint32
func (e _ErrorCode) Error() string { func (e _ErrorCode) Error() string {
return util.ErrorCodeString(uint32(e)) return util.ErrorCodeString(e)
} }
const ( const (

View File

@@ -40,7 +40,7 @@ func evalSymlinks(path string) (string, error) {
func (vfsOS) Delete(path string, syncDir bool) error { func (vfsOS) Delete(path string, syncDir bool) error {
err := os.Remove(path) err := os.Remove(path)
if errors.Is(err, fs.ErrNotExist) { if errors.Is(err, fs.ErrNotExist) {
return _IOERR_DELETE_NOENT return sysError{err, _IOERR_DELETE_NOENT}
} }
if err != nil { if err != nil {
return err return err
@@ -53,7 +53,7 @@ func (vfsOS) Delete(path string, syncDir bool) error {
defer f.Close() defer f.Close()
err = osSync(f, 0, SYNC_FULL) err = osSync(f, 0, SYNC_FULL)
if err != nil { if err != nil {
return _IOERR_DIR_FSYNC return sysError{err, _IOERR_DIR_FSYNC}
} }
} }
return nil return nil
@@ -108,14 +108,14 @@ func (vfsOS) OpenFilename(name *Filename, flags OpenFlag) (File, OpenFlag, error
} }
if err != nil { if err != nil {
if name == nil { if name == nil {
return nil, flags, _IOERR_GETTEMPPATH return nil, flags, sysError{err, _IOERR_GETTEMPPATH}
} }
if errors.Is(err, syscall.EISDIR) { if errors.Is(err, syscall.EISDIR) {
return nil, flags, _CANTOPEN_ISDIR return nil, flags, sysError{err, _CANTOPEN_ISDIR}
} }
if isCreate && isJournl && errors.Is(err, fs.ErrPermission) && if isCreate && isJournl && errors.Is(err, fs.ErrPermission) &&
osAccess(name.String(), ACCESS_EXISTS) != nil { osAccess(name.String(), ACCESS_EXISTS) != nil {
return nil, flags, _READONLY_DIRECTORY return nil, flags, sysError{err, _READONLY_DIRECTORY}
} }
return nil, flags, err return nil, flags, err
} }
@@ -123,7 +123,7 @@ func (vfsOS) OpenFilename(name *Filename, flags OpenFlag) (File, OpenFlag, error
if modeof := name.URIParameter("modeof"); modeof != "" { if modeof := name.URIParameter("modeof"); modeof != "" {
if err = osSetMode(f, modeof); err != nil { if err = osSetMode(f, modeof); err != nil {
f.Close() f.Close()
return nil, flags, _IOERR_FSTAT return nil, flags, sysError{err, _IOERR_FSTAT}
} }
} }
if isUnix && flags&OPEN_DELETEONCLOSE != 0 { if isUnix && flags&OPEN_DELETEONCLOSE != 0 {
@@ -193,7 +193,7 @@ func (f *vfsFile) Sync(flags SyncFlag) error {
defer d.Close() defer d.Close()
err = osSync(f.File, f.flags, flags) err = osSync(f.File, f.flags, flags)
if err != nil { if err != nil {
return _IOERR_DIR_FSYNC return sysError{err, _IOERR_DIR_FSYNC}
} }
} }
return nil return nil

View File

@@ -33,7 +33,7 @@ func osReadAt(file *os.File, p []byte, off int64) (int, error) {
unix.ERANGE, unix.ERANGE,
unix.EIO, unix.EIO,
unix.ENXIO: unix.ENXIO:
return n, _IOERR_CORRUPTFS return n, sysError{err, _IOERR_CORRUPTFS}
} }
} }
return n, err return n, err
@@ -42,7 +42,7 @@ func osReadAt(file *os.File, p []byte, off int64) (int, error) {
func osWriteAt(file *os.File, p []byte, off int64) (int, error) { func osWriteAt(file *os.File, p []byte, off int64) (int, error) {
n, err := file.WriteAt(p, off) n, err := file.WriteAt(p, off)
if errno, ok := err.(unix.Errno); ok && errno == unix.ENOSPC { if errno, ok := err.(unix.Errno); ok && errno == unix.ENOSPC {
return n, _FULL return n, sysError{err, _FULL}
} }
return n, err return n, err
} }

View File

@@ -20,7 +20,7 @@ func osWriteAt(file *os.File, p []byte, off int64) (int, error) {
case case
windows.ERROR_HANDLE_DISK_FULL, windows.ERROR_HANDLE_DISK_FULL,
windows.ERROR_DISK_FULL: windows.ERROR_DISK_FULL:
return n, _FULL return n, sysError{err, _FULL}
} }
} }
return n, err return n, err

View File

@@ -141,7 +141,7 @@ func (s *vfsShm) shmOpen() (rc _ErrorCode) {
return _OK return _OK
} }
func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (ptr_t, _ErrorCode) { func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (ptr_t, error) {
// Ensure size is a multiple of the OS page size. // Ensure size is a multiple of the OS page size.
if int(size)&(unix.Getpagesize()-1) != 0 { if int(size)&(unix.Getpagesize()-1) != 0 {
return 0, _IOERR_SHMMAP return 0, _IOERR_SHMMAP
@@ -154,26 +154,30 @@ func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, ext
// Check if file is big enough. // Check if file is big enough.
o, err := s.Seek(0, io.SeekEnd) o, err := s.Seek(0, io.SeekEnd)
if err != nil { if err != nil {
return 0, _IOERR_SHMSIZE return 0, sysError{err, _IOERR_SHMSIZE}
} }
if n := (int64(id) + 1) * int64(size); n > o { if n := (int64(id) + 1) * int64(size); n > o {
if !extend { if !extend {
return 0, _OK return 0, nil
} }
if osAllocate(s.File, n) != nil { if err := osAllocate(s.File, n); err != nil {
return 0, _IOERR_SHMSIZE return 0, sysError{err, _IOERR_SHMSIZE}
} }
} }
r, err := util.MapRegion(ctx, mod, s.File, int64(id)*int64(size), size, false) r, err := util.MapRegion(ctx, mod, s.File, int64(id)*int64(size), size, false)
if err != nil { if err != nil {
return 0, _IOERR_SHMMAP return 0, err
} }
s.regions = append(s.regions, r) s.regions = append(s.regions, r)
return r.Ptr, _OK return r.Ptr, nil
}
func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) error {
if s.vfsShmParent == nil {
return _IOERR_SHMLOCK
} }
func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) _ErrorCode {
s.Lock() s.Lock()
defer s.Unlock() defer s.Unlock()

View File

@@ -31,8 +31,8 @@ const (
// //
// https://sqlite.org/walformat.html#the_wal_index_file_format // https://sqlite.org/walformat.html#the_wal_index_file_format
func (s *vfsShm) shmAcquire(ptr *_ErrorCode) { func (s *vfsShm) shmAcquire(errp *error) {
if ptr != nil && *ptr != _OK { if errp != nil && *errp != _OK {
return return
} }
if len(s.ptrs) == 0 || shmEqual(s.shadow[0][:], s.shared[0][:]) { if len(s.ptrs) == 0 || shmEqual(s.shadow[0][:], s.shared[0][:]) {

View File

@@ -59,7 +59,7 @@ func (s *vfsShm) Close() error {
} }
if err := dotlk.Unlock(s.path); err != nil { if err := dotlk.Unlock(s.path); err != nil {
return _IOERR_UNLOCK return sysError{err, _IOERR_UNLOCK}
} }
delete(vfsShmList, s.path) delete(vfsShmList, s.path)
s.vfsShmParent = nil s.vfsShmParent = nil
@@ -96,7 +96,7 @@ func (s *vfsShm) shmOpen() _ErrorCode {
return _OK return _OK
} }
func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (ptr_t, _ErrorCode) { func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (ptr_t, error) {
if size != _WALINDEX_PGSZ { if size != _WALINDEX_PGSZ {
return 0, _IOERR_SHMMAP return 0, _IOERR_SHMMAP
} }
@@ -116,7 +116,7 @@ func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, ext
// Extend shared memory. // Extend shared memory.
if int(id) >= len(s.shared) { if int(id) >= len(s.shared) {
if !extend { if !extend {
return 0, _OK return 0, nil
} }
s.shared = append(s.shared, make([][_WALINDEX_PGSZ]byte, int(id)-len(s.shared)+1)...) s.shared = append(s.shared, make([][_WALINDEX_PGSZ]byte, int(id)-len(s.shared)+1)...)
} }
@@ -140,16 +140,20 @@ func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, ext
} }
s.shadow[0][4] = 1 s.shadow[0][4] = 1
return s.ptrs[id], _OK return s.ptrs[id], nil
}
func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) (err error) {
if s.vfsShmParent == nil {
return _IOERR_SHMLOCK
} }
func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) (rc _ErrorCode) {
s.Lock() s.Lock()
defer s.Unlock() defer s.Unlock()
switch { switch {
case flags&_SHM_LOCK != 0: case flags&_SHM_LOCK != 0:
defer s.shmAcquire(&rc) defer s.shmAcquire(&err)
case flags&_SHM_EXCLUSIVE != 0: case flags&_SHM_EXCLUSIVE != 0:
s.shmRelease() s.shmRelease()
} }

View File

@@ -73,7 +73,7 @@ func (s *vfsShm) shmOpen() _ErrorCode {
return rc return rc
} }
func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (ptr_t, _ErrorCode) { func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (ptr_t, error) {
// Ensure size is a multiple of the OS page size. // Ensure size is a multiple of the OS page size.
if int(size)&(unix.Getpagesize()-1) != 0 { if int(size)&(unix.Getpagesize()-1) != 0 {
return 0, _IOERR_SHMMAP return 0, _IOERR_SHMMAP
@@ -86,29 +86,32 @@ func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, ext
// Check if file is big enough. // Check if file is big enough.
o, err := s.Seek(0, io.SeekEnd) o, err := s.Seek(0, io.SeekEnd)
if err != nil { if err != nil {
return 0, _IOERR_SHMSIZE return 0, sysError{err, _IOERR_SHMSIZE}
} }
if n := (int64(id) + 1) * int64(size); n > o { if n := (int64(id) + 1) * int64(size); n > o {
if !extend { if !extend {
return 0, _OK return 0, nil
} }
if s.readOnly || osAllocate(s.File, n) != nil { if s.readOnly {
return 0, _IOERR_SHMSIZE return 0, _IOERR_SHMSIZE
} }
if err := osAllocate(s.File, n); err != nil {
return 0, sysError{err, _IOERR_SHMSIZE}
}
} }
r, err := util.MapRegion(ctx, mod, s.File, int64(id)*int64(size), size, s.readOnly) r, err := util.MapRegion(ctx, mod, s.File, int64(id)*int64(size), size, s.readOnly)
if err != nil { if err != nil {
return 0, _IOERR_SHMMAP return 0, err
} }
s.regions = append(s.regions, r) s.regions = append(s.regions, r)
if s.readOnly { if s.readOnly {
return r.Ptr, _READONLY return r.Ptr, _READONLY
} }
return r.Ptr, _OK return r.Ptr, nil
} }
func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) _ErrorCode { func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) error {
// Argument check. // Argument check.
switch { switch {
case n <= 0: case n <= 0:
@@ -129,6 +132,10 @@ func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) _ErrorCode {
panic(util.AssertErr()) panic(util.AssertErr())
} }
if s.File == nil {
return _IOERR_SHMLOCK
}
var timeout time.Duration var timeout time.Duration
if s.blocking { if s.blocking {
timeout = time.Millisecond timeout = time.Millisecond

View File

@@ -65,7 +65,7 @@ func (s *vfsShm) shmOpen() _ErrorCode {
return rc return rc
} }
func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (_ ptr_t, rc _ErrorCode) { func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (_ ptr_t, err error) {
// Ensure size is a multiple of the OS page size. // Ensure size is a multiple of the OS page size.
if size != _WALINDEX_PGSZ || (windows.Getpagesize()-1)&_WALINDEX_PGSZ != 0 { if size != _WALINDEX_PGSZ || (windows.Getpagesize()-1)&_WALINDEX_PGSZ != 0 {
return 0, _IOERR_SHMMAP return 0, _IOERR_SHMMAP
@@ -79,19 +79,19 @@ func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, ext
return 0, rc return 0, rc
} }
defer s.shmAcquire(&rc) defer s.shmAcquire(&err)
// Check if file is big enough. // Check if file is big enough.
o, err := s.Seek(0, io.SeekEnd) o, err := s.Seek(0, io.SeekEnd)
if err != nil { if err != nil {
return 0, _IOERR_SHMSIZE return 0, sysError{err, _IOERR_SHMSIZE}
} }
if n := (int64(id) + 1) * int64(size); n > o { if n := (int64(id) + 1) * int64(size); n > o {
if !extend { if !extend {
return 0, _OK return 0, nil
} }
if osAllocate(s.File, n) != nil { if err := osAllocate(s.File, n); err != nil {
return 0, _IOERR_SHMSIZE return 0, sysError{err, _IOERR_SHMSIZE}
} }
} }
@@ -99,7 +99,7 @@ func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, ext
for int(id) >= len(s.shared) { for int(id) >= len(s.shared) {
r, err := util.MapRegion(ctx, mod, s.File, int64(id)*int64(size), size) r, err := util.MapRegion(ctx, mod, s.File, int64(id)*int64(size), size)
if err != nil { if err != nil {
return 0, _IOERR_SHMMAP return 0, err
} }
s.regions = append(s.regions, r) s.regions = append(s.regions, r)
s.shared = append(s.shared, r.Data) s.shared = append(s.shared, r.Data)
@@ -124,13 +124,17 @@ func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, ext
} }
s.shadow[0][4] = 1 s.shadow[0][4] = 1
return s.ptrs[id], _OK return s.ptrs[id], nil
}
func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) (err error) {
if s.File == nil {
return _IOERR_SHMLOCK
} }
func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) (rc _ErrorCode) {
switch { switch {
case flags&_SHM_LOCK != 0: case flags&_SHM_LOCK != 0:
defer s.shmAcquire(&rc) defer s.shmAcquire(&err)
case flags&_SHM_EXCLUSIVE != 0: case flags&_SHM_EXCLUSIVE != 0:
s.shmRelease() s.shmRelease()
} }

View File

@@ -102,7 +102,7 @@ func vfsFullPathname(ctx context.Context, mod api.Module, pVfs, zRelative ptr_t,
} }
util.WriteString(mod, zFull, path) util.WriteString(mod, zFull, path)
return vfsErrorCode(err, _CANTOPEN_FULLPATH) return vfsErrorCode(ctx, err, _CANTOPEN_FULLPATH)
} }
func vfsDelete(ctx context.Context, mod api.Module, pVfs, zPath ptr_t, syncDir int32) _ErrorCode { func vfsDelete(ctx context.Context, mod api.Module, pVfs, zPath ptr_t, syncDir int32) _ErrorCode {
@@ -110,7 +110,7 @@ func vfsDelete(ctx context.Context, mod api.Module, pVfs, zPath ptr_t, syncDir i
path := util.ReadString(mod, zPath, _MAX_PATHNAME) path := util.ReadString(mod, zPath, _MAX_PATHNAME)
err := vfs.Delete(path, syncDir != 0) err := vfs.Delete(path, syncDir != 0)
return vfsErrorCode(err, _IOERR_DELETE) return vfsErrorCode(ctx, err, _IOERR_DELETE)
} }
func vfsAccess(ctx context.Context, mod api.Module, pVfs, zPath ptr_t, flags AccessFlag, pResOut ptr_t) _ErrorCode { func vfsAccess(ctx context.Context, mod api.Module, pVfs, zPath ptr_t, flags AccessFlag, pResOut ptr_t) _ErrorCode {
@@ -119,7 +119,7 @@ func vfsAccess(ctx context.Context, mod api.Module, pVfs, zPath ptr_t, flags Acc
ok, err := vfs.Access(path, flags) ok, err := vfs.Access(path, flags)
util.WriteBool(mod, pResOut, ok) util.WriteBool(mod, pResOut, ok)
return vfsErrorCode(err, _IOERR_ACCESS) return vfsErrorCode(ctx, err, _IOERR_ACCESS)
} }
func vfsOpen(ctx context.Context, mod api.Module, pVfs, zPath, pFile ptr_t, flags OpenFlag, pOutFlags, pOutVFS ptr_t) _ErrorCode { func vfsOpen(ctx context.Context, mod api.Module, pVfs, zPath, pFile ptr_t, flags OpenFlag, pOutFlags, pOutVFS ptr_t) _ErrorCode {
@@ -134,7 +134,7 @@ func vfsOpen(ctx context.Context, mod api.Module, pVfs, zPath, pFile ptr_t, flag
file, flags, err = vfs.Open(name.String(), flags) file, flags, err = vfs.Open(name.String(), flags)
} }
if err != nil { if err != nil {
return vfsErrorCode(err, _CANTOPEN) return vfsErrorCode(ctx, err, _CANTOPEN)
} }
if file, ok := file.(FilePowersafeOverwrite); ok { if file, ok := file.(FilePowersafeOverwrite); ok {
@@ -155,7 +155,7 @@ func vfsOpen(ctx context.Context, mod api.Module, pVfs, zPath, pFile ptr_t, flag
func vfsClose(ctx context.Context, mod api.Module, pFile ptr_t) _ErrorCode { func vfsClose(ctx context.Context, mod api.Module, pFile ptr_t) _ErrorCode {
err := vfsFileClose(ctx, mod, pFile) err := vfsFileClose(ctx, mod, pFile)
return vfsErrorCode(err, _IOERR_CLOSE) return vfsErrorCode(ctx, err, _IOERR_CLOSE)
} }
func vfsRead(ctx context.Context, mod api.Module, pFile, zBuf ptr_t, iAmt int32, iOfst int64) _ErrorCode { func vfsRead(ctx context.Context, mod api.Module, pFile, zBuf ptr_t, iAmt int32, iOfst int64) _ErrorCode {
@@ -167,7 +167,7 @@ func vfsRead(ctx context.Context, mod api.Module, pFile, zBuf ptr_t, iAmt int32,
return _OK return _OK
} }
if err != io.EOF { if err != io.EOF {
return vfsErrorCode(err, _IOERR_READ) return vfsErrorCode(ctx, err, _IOERR_READ)
} }
clear(buf[n:]) clear(buf[n:])
return _IOERR_SHORT_READ return _IOERR_SHORT_READ
@@ -178,45 +178,45 @@ func vfsWrite(ctx context.Context, mod api.Module, pFile, zBuf ptr_t, iAmt int32
buf := util.View(mod, zBuf, int64(iAmt)) buf := util.View(mod, zBuf, int64(iAmt))
_, err := file.WriteAt(buf, iOfst) _, err := file.WriteAt(buf, iOfst)
return vfsErrorCode(err, _IOERR_WRITE) return vfsErrorCode(ctx, err, _IOERR_WRITE)
} }
func vfsTruncate(ctx context.Context, mod api.Module, pFile ptr_t, nByte int64) _ErrorCode { func vfsTruncate(ctx context.Context, mod api.Module, pFile ptr_t, nByte int64) _ErrorCode {
file := vfsFileGet(ctx, mod, pFile).(File) file := vfsFileGet(ctx, mod, pFile).(File)
err := file.Truncate(nByte) err := file.Truncate(nByte)
return vfsErrorCode(err, _IOERR_TRUNCATE) return vfsErrorCode(ctx, err, _IOERR_TRUNCATE)
} }
func vfsSync(ctx context.Context, mod api.Module, pFile ptr_t, flags SyncFlag) _ErrorCode { func vfsSync(ctx context.Context, mod api.Module, pFile ptr_t, flags SyncFlag) _ErrorCode {
file := vfsFileGet(ctx, mod, pFile).(File) file := vfsFileGet(ctx, mod, pFile).(File)
err := file.Sync(flags) err := file.Sync(flags)
return vfsErrorCode(err, _IOERR_FSYNC) return vfsErrorCode(ctx, err, _IOERR_FSYNC)
} }
func vfsFileSize(ctx context.Context, mod api.Module, pFile, pSize ptr_t) _ErrorCode { func vfsFileSize(ctx context.Context, mod api.Module, pFile, pSize ptr_t) _ErrorCode {
file := vfsFileGet(ctx, mod, pFile).(File) file := vfsFileGet(ctx, mod, pFile).(File)
size, err := file.Size() size, err := file.Size()
util.Write64(mod, pSize, size) util.Write64(mod, pSize, size)
return vfsErrorCode(err, _IOERR_SEEK) return vfsErrorCode(ctx, err, _IOERR_SEEK)
} }
func vfsLock(ctx context.Context, mod api.Module, pFile ptr_t, eLock LockLevel) _ErrorCode { func vfsLock(ctx context.Context, mod api.Module, pFile ptr_t, eLock LockLevel) _ErrorCode {
file := vfsFileGet(ctx, mod, pFile).(File) file := vfsFileGet(ctx, mod, pFile).(File)
err := file.Lock(eLock) err := file.Lock(eLock)
return vfsErrorCode(err, _IOERR_LOCK) return vfsErrorCode(ctx, err, _IOERR_LOCK)
} }
func vfsUnlock(ctx context.Context, mod api.Module, pFile ptr_t, eLock LockLevel) _ErrorCode { func vfsUnlock(ctx context.Context, mod api.Module, pFile ptr_t, eLock LockLevel) _ErrorCode {
file := vfsFileGet(ctx, mod, pFile).(File) file := vfsFileGet(ctx, mod, pFile).(File)
err := file.Unlock(eLock) err := file.Unlock(eLock)
return vfsErrorCode(err, _IOERR_UNLOCK) return vfsErrorCode(ctx, err, _IOERR_UNLOCK)
} }
func vfsCheckReservedLock(ctx context.Context, mod api.Module, pFile, pResOut ptr_t) _ErrorCode { func vfsCheckReservedLock(ctx context.Context, mod api.Module, pFile, pResOut ptr_t) _ErrorCode {
file := vfsFileGet(ctx, mod, pFile).(File) file := vfsFileGet(ctx, mod, pFile).(File)
locked, err := file.CheckReservedLock() locked, err := file.CheckReservedLock()
util.WriteBool(mod, pResOut, locked) util.WriteBool(mod, pResOut, locked)
return vfsErrorCode(err, _IOERR_CHECKRESERVEDLOCK) return vfsErrorCode(ctx, err, _IOERR_CHECKRESERVEDLOCK)
} }
func vfsFileControl(ctx context.Context, mod api.Module, pFile ptr_t, op _FcntlOpcode, pArg ptr_t) _ErrorCode { func vfsFileControl(ctx context.Context, mod api.Module, pFile ptr_t, op _FcntlOpcode, pArg ptr_t) _ErrorCode {
@@ -268,20 +268,20 @@ func vfsFileControlImpl(ctx context.Context, mod api.Module, file File, op _Fcnt
if file, ok := file.(FileSizeHint); ok { if file, ok := file.(FileSizeHint); ok {
size := util.Read64[int64](mod, pArg) size := util.Read64[int64](mod, pArg)
err := file.SizeHint(size) err := file.SizeHint(size)
return vfsErrorCode(err, _IOERR_TRUNCATE) return vfsErrorCode(ctx, err, _IOERR_TRUNCATE)
} }
case _FCNTL_HAS_MOVED: case _FCNTL_HAS_MOVED:
if file, ok := file.(FileHasMoved); ok { if file, ok := file.(FileHasMoved); ok {
moved, err := file.HasMoved() moved, err := file.HasMoved()
util.WriteBool(mod, pArg, moved) util.WriteBool(mod, pArg, moved)
return vfsErrorCode(err, _IOERR_FSTAT) return vfsErrorCode(ctx, err, _IOERR_FSTAT)
} }
case _FCNTL_OVERWRITE: case _FCNTL_OVERWRITE:
if file, ok := file.(FileOverwrite); ok { if file, ok := file.(FileOverwrite); ok {
err := file.Overwrite() err := file.Overwrite()
return vfsErrorCode(err, _IOERR) return vfsErrorCode(ctx, err, _IOERR)
} }
case _FCNTL_SYNC: case _FCNTL_SYNC:
@@ -291,29 +291,29 @@ func vfsFileControlImpl(ctx context.Context, mod api.Module, file File, op _Fcnt
name = util.ReadString(mod, pArg, _MAX_PATHNAME) name = util.ReadString(mod, pArg, _MAX_PATHNAME)
} }
err := file.SyncSuper(name) err := file.SyncSuper(name)
return vfsErrorCode(err, _IOERR) return vfsErrorCode(ctx, err, _IOERR)
} }
case _FCNTL_COMMIT_PHASETWO: case _FCNTL_COMMIT_PHASETWO:
if file, ok := file.(FileCommitPhaseTwo); ok { if file, ok := file.(FileCommitPhaseTwo); ok {
err := file.CommitPhaseTwo() err := file.CommitPhaseTwo()
return vfsErrorCode(err, _IOERR) return vfsErrorCode(ctx, err, _IOERR)
} }
case _FCNTL_BEGIN_ATOMIC_WRITE: case _FCNTL_BEGIN_ATOMIC_WRITE:
if file, ok := file.(FileBatchAtomicWrite); ok { if file, ok := file.(FileBatchAtomicWrite); ok {
err := file.BeginAtomicWrite() err := file.BeginAtomicWrite()
return vfsErrorCode(err, _IOERR_BEGIN_ATOMIC) return vfsErrorCode(ctx, err, _IOERR_BEGIN_ATOMIC)
} }
case _FCNTL_COMMIT_ATOMIC_WRITE: case _FCNTL_COMMIT_ATOMIC_WRITE:
if file, ok := file.(FileBatchAtomicWrite); ok { if file, ok := file.(FileBatchAtomicWrite); ok {
err := file.CommitAtomicWrite() err := file.CommitAtomicWrite()
return vfsErrorCode(err, _IOERR_COMMIT_ATOMIC) return vfsErrorCode(ctx, err, _IOERR_COMMIT_ATOMIC)
} }
case _FCNTL_ROLLBACK_ATOMIC_WRITE: case _FCNTL_ROLLBACK_ATOMIC_WRITE:
if file, ok := file.(FileBatchAtomicWrite); ok { if file, ok := file.(FileBatchAtomicWrite); ok {
err := file.RollbackAtomicWrite() err := file.RollbackAtomicWrite()
return vfsErrorCode(err, _IOERR_ROLLBACK_ATOMIC) return vfsErrorCode(ctx, err, _IOERR_ROLLBACK_ATOMIC)
} }
case _FCNTL_CKPT_START: case _FCNTL_CKPT_START:
@@ -338,7 +338,7 @@ func vfsFileControlImpl(ctx context.Context, mod api.Module, file File, op _Fcnt
out, err := file.Pragma(strings.ToLower(name), value) out, err := file.Pragma(strings.ToLower(name), value)
ret := vfsErrorCode(err, _ERROR) ret := vfsErrorCode(ctx, err, _ERROR)
if ret == _ERROR { if ret == _ERROR {
out = err.Error() out = err.Error()
} }
@@ -407,14 +407,15 @@ func vfsShmBarrier(ctx context.Context, mod api.Module, pFile ptr_t) {
func vfsShmMap(ctx context.Context, mod api.Module, pFile ptr_t, iRegion, szRegion, bExtend int32, pp ptr_t) _ErrorCode { func vfsShmMap(ctx context.Context, mod api.Module, pFile ptr_t, iRegion, szRegion, bExtend int32, pp ptr_t) _ErrorCode {
shm := vfsFileGet(ctx, mod, pFile).(FileSharedMemory).SharedMemory() shm := vfsFileGet(ctx, mod, pFile).(FileSharedMemory).SharedMemory()
p, rc := shm.shmMap(ctx, mod, iRegion, szRegion, bExtend != 0) p, err := shm.shmMap(ctx, mod, iRegion, szRegion, bExtend != 0)
util.Write32(mod, pp, p) util.Write32(mod, pp, p)
return rc return vfsErrorCode(ctx, err, _IOERR_SHMMAP)
} }
func vfsShmLock(ctx context.Context, mod api.Module, pFile ptr_t, offset, n int32, flags _ShmFlag) _ErrorCode { func vfsShmLock(ctx context.Context, mod api.Module, pFile ptr_t, offset, n int32, flags _ShmFlag) _ErrorCode {
shm := vfsFileGet(ctx, mod, pFile).(FileSharedMemory).SharedMemory() shm := vfsFileGet(ctx, mod, pFile).(FileSharedMemory).SharedMemory()
return shm.shmLock(offset, n, flags) err := shm.shmLock(offset, n, flags)
return vfsErrorCode(ctx, err, _IOERR_SHMLOCK)
} }
func vfsShmUnmap(ctx context.Context, mod api.Module, pFile ptr_t, bDelete int32) _ErrorCode { func vfsShmUnmap(ctx context.Context, mod api.Module, pFile ptr_t, bDelete int32) _ErrorCode {
@@ -454,13 +455,36 @@ func vfsFileClose(ctx context.Context, mod api.Module, pFile ptr_t) error {
return util.DelHandle(ctx, id) return util.DelHandle(ctx, id)
} }
func vfsErrorCode(err error, def _ErrorCode) _ErrorCode { func vfsErrorCode(ctx context.Context, err error, code _ErrorCode) _ErrorCode {
if err == nil { var sys error
return _OK
} switch err := err.(type) {
case nil:
code = _OK
case _ErrorCode:
code = err
case sysError:
code = err.code
sys = err.error
default:
switch v := reflect.ValueOf(err); v.Kind() { switch v := reflect.ValueOf(err); v.Kind() {
case reflect.Uint8, reflect.Uint16, reflect.Uint32: case reflect.Uint8, reflect.Uint16:
return _ErrorCode(v.Uint()) code = _ErrorCode(v.Uint())
} }
return def }
util.SetSystemError(ctx, sys)
return code
}
func SystemError[T interface{ ~uint8 | ~uint16 }](err error, code T) error {
if err == nil {
return nil
}
return sysError{error: err, code: _ErrorCode(code)}
}
type sysError struct {
error
code _ErrorCode
} }

48
vtab.go
View File

@@ -465,19 +465,19 @@ func vtabModuleCallback(i vtabConstructor) func(_ context.Context, _ api.Module,
vtabPutHandle(ctx, mod, ppVTab, val[0].Interface()) vtabPutHandle(ctx, mod, ppVTab, val[0].Interface())
} }
return vtabError(ctx, mod, pzErr, _PTR_ERROR, err) return vtabError(ctx, mod, pzErr, _PTR_ERROR, err, ERROR)
} }
} }
func vtabDisconnectCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t { func vtabDisconnectCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t {
err := vtabDelHandle(ctx, mod, pVTab) err := vtabDelHandle(ctx, mod, pVTab)
return vtabError(ctx, mod, 0, _PTR_ERROR, err) return vtabError(ctx, mod, 0, _PTR_ERROR, err, ERROR)
} }
func vtabDestroyCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t { func vtabDestroyCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t {
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabDestroyer) vtab := vtabGetHandle(ctx, mod, pVTab).(VTabDestroyer)
err := errors.Join(vtab.Destroy(), vtabDelHandle(ctx, mod, pVTab)) err := errors.Join(vtab.Destroy(), vtabDelHandle(ctx, mod, pVTab))
return vtabError(ctx, mod, 0, _PTR_ERROR, err) return vtabError(ctx, mod, 0, _PTR_ERROR, err, ERROR)
} }
func vtabBestIndexCallback(ctx context.Context, mod api.Module, pVTab, pIdxInfo ptr_t) res_t { func vtabBestIndexCallback(ctx context.Context, mod api.Module, pVTab, pIdxInfo ptr_t) res_t {
@@ -490,7 +490,7 @@ func vtabBestIndexCallback(ctx context.Context, mod api.Module, pVTab, pIdxInfo
err := vtab.BestIndex(&info) err := vtab.BestIndex(&info)
info.save() info.save()
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err) return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err, ERROR)
} }
func vtabUpdateCallback(ctx context.Context, mod api.Module, pVTab ptr_t, nArg int32, pArg, pRowID ptr_t) res_t { func vtabUpdateCallback(ctx context.Context, mod api.Module, pVTab ptr_t, nArg int32, pArg, pRowID ptr_t) res_t {
@@ -504,13 +504,13 @@ func vtabUpdateCallback(ctx context.Context, mod api.Module, pVTab ptr_t, nArg i
util.Write64(mod, pRowID, rowID) util.Write64(mod, pRowID, rowID)
} }
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err) return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err, ERROR)
} }
func vtabRenameCallback(ctx context.Context, mod api.Module, pVTab, zNew ptr_t) res_t { func vtabRenameCallback(ctx context.Context, mod api.Module, pVTab, zNew ptr_t) res_t {
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabRenamer) vtab := vtabGetHandle(ctx, mod, pVTab).(VTabRenamer)
err := vtab.Rename(util.ReadString(mod, zNew, _MAX_NAME)) err := vtab.Rename(util.ReadString(mod, zNew, _MAX_NAME))
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err) return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err, ERROR)
} }
func vtabFindFuncCallback(ctx context.Context, mod api.Module, pVTab ptr_t, nArg int32, zName, pxFunc ptr_t) int32 { func vtabFindFuncCallback(ctx context.Context, mod api.Module, pVTab ptr_t, nArg int32, zName, pxFunc ptr_t) int32 {
@@ -534,51 +534,49 @@ func vtabIntegrityCallback(ctx context.Context, mod api.Module, pVTab, zSchema,
err := vtab.Integrity(schema, table, int(mFlags)) err := vtab.Integrity(schema, table, int(mFlags))
// xIntegrity should return OK - even if it finds problems in the content of the virtual table. // xIntegrity should return OK - even if it finds problems in the content of the virtual table.
// https://sqlite.org/vtab.html#xintegrity // https://sqlite.org/vtab.html#xintegrity
vtabError(ctx, mod, pzErr, _PTR_ERROR, err) return vtabError(ctx, mod, pzErr, _PTR_ERROR, err, _OK)
_, code := errorCode(err, _OK)
return code
} }
func vtabBeginCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t { func vtabBeginCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t {
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabTxn) vtab := vtabGetHandle(ctx, mod, pVTab).(VTabTxn)
err := vtab.Begin() err := vtab.Begin()
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err) return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err, ERROR)
} }
func vtabSyncCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t { func vtabSyncCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t {
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabTxn) vtab := vtabGetHandle(ctx, mod, pVTab).(VTabTxn)
err := vtab.Sync() err := vtab.Sync()
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err) return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err, ERROR)
} }
func vtabCommitCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t { func vtabCommitCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t {
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabTxn) vtab := vtabGetHandle(ctx, mod, pVTab).(VTabTxn)
err := vtab.Commit() err := vtab.Commit()
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err) return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err, ERROR)
} }
func vtabRollbackCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t { func vtabRollbackCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t {
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabTxn) vtab := vtabGetHandle(ctx, mod, pVTab).(VTabTxn)
err := vtab.Rollback() err := vtab.Rollback()
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err) return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err, ERROR)
} }
func vtabSavepointCallback(ctx context.Context, mod api.Module, pVTab ptr_t, id int32) res_t { func vtabSavepointCallback(ctx context.Context, mod api.Module, pVTab ptr_t, id int32) res_t {
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabSavepointer) vtab := vtabGetHandle(ctx, mod, pVTab).(VTabSavepointer)
err := vtab.Savepoint(int(id)) err := vtab.Savepoint(int(id))
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err) return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err, ERROR)
} }
func vtabReleaseCallback(ctx context.Context, mod api.Module, pVTab ptr_t, id int32) res_t { func vtabReleaseCallback(ctx context.Context, mod api.Module, pVTab ptr_t, id int32) res_t {
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabSavepointer) vtab := vtabGetHandle(ctx, mod, pVTab).(VTabSavepointer)
err := vtab.Release(int(id)) err := vtab.Release(int(id))
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err) return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err, ERROR)
} }
func vtabRollbackToCallback(ctx context.Context, mod api.Module, pVTab ptr_t, id int32) res_t { func vtabRollbackToCallback(ctx context.Context, mod api.Module, pVTab ptr_t, id int32) res_t {
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabSavepointer) vtab := vtabGetHandle(ctx, mod, pVTab).(VTabSavepointer)
err := vtab.RollbackTo(int(id)) err := vtab.RollbackTo(int(id))
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err) return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err, ERROR)
} }
func cursorOpenCallback(ctx context.Context, mod api.Module, pVTab, ppCur ptr_t) res_t { func cursorOpenCallback(ctx context.Context, mod api.Module, pVTab, ppCur ptr_t) res_t {
@@ -589,12 +587,12 @@ func cursorOpenCallback(ctx context.Context, mod api.Module, pVTab, ppCur ptr_t)
vtabPutHandle(ctx, mod, ppCur, cursor) vtabPutHandle(ctx, mod, ppCur, cursor)
} }
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err) return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err, ERROR)
} }
func cursorCloseCallback(ctx context.Context, mod api.Module, pCur ptr_t) res_t { func cursorCloseCallback(ctx context.Context, mod api.Module, pCur ptr_t) res_t {
err := vtabDelHandle(ctx, mod, pCur) err := vtabDelHandle(ctx, mod, pCur)
return vtabError(ctx, mod, 0, _VTAB_ERROR, err) return vtabError(ctx, mod, 0, _PTR_ERROR, err, ERROR)
} }
func cursorFilterCallback(ctx context.Context, mod api.Module, pCur ptr_t, idxNum int32, idxStr ptr_t, nArg int32, pArg ptr_t) res_t { func cursorFilterCallback(ctx context.Context, mod api.Module, pCur ptr_t, idxNum int32, idxStr ptr_t, nArg int32, pArg ptr_t) res_t {
@@ -609,7 +607,7 @@ func cursorFilterCallback(ctx context.Context, mod api.Module, pCur ptr_t, idxNu
cursor := vtabGetHandle(ctx, mod, pCur).(VTabCursor) cursor := vtabGetHandle(ctx, mod, pCur).(VTabCursor)
err := cursor.Filter(int(idxNum), idxName, *args...) err := cursor.Filter(int(idxNum), idxName, *args...)
return vtabError(ctx, mod, pCur, _CURSOR_ERROR, err) return vtabError(ctx, mod, pCur, _CURSOR_ERROR, err, ERROR)
} }
func cursorEOFCallback(ctx context.Context, mod api.Module, pCur ptr_t) int32 { func cursorEOFCallback(ctx context.Context, mod api.Module, pCur ptr_t) int32 {
@@ -623,14 +621,14 @@ func cursorEOFCallback(ctx context.Context, mod api.Module, pCur ptr_t) int32 {
func cursorNextCallback(ctx context.Context, mod api.Module, pCur ptr_t) res_t { func cursorNextCallback(ctx context.Context, mod api.Module, pCur ptr_t) res_t {
cursor := vtabGetHandle(ctx, mod, pCur).(VTabCursor) cursor := vtabGetHandle(ctx, mod, pCur).(VTabCursor)
err := cursor.Next() err := cursor.Next()
return vtabError(ctx, mod, pCur, _CURSOR_ERROR, err) return vtabError(ctx, mod, pCur, _CURSOR_ERROR, err, ERROR)
} }
func cursorColumnCallback(ctx context.Context, mod api.Module, pCur, pCtx ptr_t, n int32) res_t { func cursorColumnCallback(ctx context.Context, mod api.Module, pCur, pCtx ptr_t, n int32) res_t {
cursor := vtabGetHandle(ctx, mod, pCur).(VTabCursor) cursor := vtabGetHandle(ctx, mod, pCur).(VTabCursor)
db := ctx.Value(connKey{}).(*Conn) db := ctx.Value(connKey{}).(*Conn)
err := cursor.Column(Context{db, pCtx}, int(n)) err := cursor.Column(Context{db, pCtx}, int(n))
return vtabError(ctx, mod, pCur, _CURSOR_ERROR, err) return vtabError(ctx, mod, pCur, _CURSOR_ERROR, err, ERROR)
} }
func cursorRowIDCallback(ctx context.Context, mod api.Module, pCur, pRowID ptr_t) res_t { func cursorRowIDCallback(ctx context.Context, mod api.Module, pCur, pRowID ptr_t) res_t {
@@ -641,7 +639,7 @@ func cursorRowIDCallback(ctx context.Context, mod api.Module, pCur, pRowID ptr_t
util.Write64(mod, pRowID, rowID) util.Write64(mod, pRowID, rowID)
} }
return vtabError(ctx, mod, pCur, _CURSOR_ERROR, err) return vtabError(ctx, mod, pCur, _CURSOR_ERROR, err, ERROR)
} }
const ( const (
@@ -650,10 +648,10 @@ const (
_CURSOR_ERROR _CURSOR_ERROR
) )
func vtabError(ctx context.Context, mod api.Module, ptr ptr_t, kind uint32, err error) res_t { func vtabError(ctx context.Context, mod api.Module, ptr ptr_t, kind uint32, err error, def ErrorCode) res_t {
const zErrMsgOffset = 8 const zErrMsgOffset = 8
msg, code := errorCode(err, ERROR) msg, code := errorCode(err, def)
if msg != "" && ptr != 0 { if ptr != 0 && msg != "" {
switch kind { switch kind {
case _VTAB_ERROR: case _VTAB_ERROR:
ptr = ptr + zErrMsgOffset // zErrMsg ptr = ptr + zErrMsgOffset // zErrMsg