Skip to content

Commit 1db4366

Browse files
committed
VFS error handling.
1 parent 9e1cbfb commit 1db4366

File tree

21 files changed

+208
-129
lines changed

21 files changed

+208
-129
lines changed

config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ func traceCallback(ctx context.Context, mod api.Module, evt TraceEvent, pDB, pAr
265265
}
266266
}
267267
if arg1 != nil {
268-
_, rc = errorCode(c.trace(evt, arg1, arg2), ERROR)
268+
_ = c.trace(evt, arg1, arg2)
269269
}
270270
}
271271
return rc

context.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,14 +198,14 @@ func (ctx Context) ResultError(err error) {
198198
return
199199
}
200200

201-
msg, code := errorCode(err, _OK)
201+
msg, code := errorCode(err, ERROR)
202202
if msg != "" {
203203
defer ctx.c.arena.mark()()
204204
ptr := ctx.c.arena.string(msg)
205205
ctx.c.call("sqlite3_result_error",
206206
stk_t(ctx.handle), stk_t(ptr), stk_t(len(msg)))
207207
}
208-
if code != _OK {
208+
if code != res_t(ERROR) {
209209
ctx.c.call("sqlite3_result_error_code",
210210
stk_t(ctx.handle), stk_t(code))
211211
}

driver/driver_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ func Test_Open_dir(t *testing.T) {
4444
if err == nil {
4545
t.Fatal("want error")
4646
}
47-
if !errors.Is(err, sqlite3.CANTOPEN) {
48-
t.Errorf("got %v, want sqlite3.CANTOPEN", err)
47+
if !errors.Is(err, sqlite3.CANTOPEN_ISDIR) {
48+
t.Errorf("got %v, want sqlite3.CANTOPEN_ISDIR", err)
4949
}
5050
}
5151

error.go

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
//
1212
// https://sqlite.org/c3ref/errcode.html
1313
type Error struct {
14+
sys error
1415
msg string
1516
sql string
1617
code res_t
@@ -33,7 +34,7 @@ func (e *Error) ExtendedCode() ExtendedErrorCode {
3334
// Error implements the error interface.
3435
func (e *Error) Error() string {
3536
var b strings.Builder
36-
b.WriteString(util.ErrorCodeString(uint32(e.code)))
37+
b.WriteString(util.ErrorCodeString(e.code))
3738

3839
if e.msg != "" {
3940
b.WriteString(": ")
@@ -43,6 +44,14 @@ func (e *Error) Error() string {
4344
return b.String()
4445
}
4546

47+
// Unwrap returns the underlying operating system error
48+
// that caused the I/O error or failure to open a file.
49+
//
50+
// https://sqlite.org/c3ref/system_errno.html
51+
func (e *Error) Unwrap() error {
52+
return e.sys
53+
}
54+
4655
// Is tests whether this error matches a given [ErrorCode] or [ExtendedErrorCode].
4756
//
4857
// It makes it possible to do:
@@ -90,7 +99,16 @@ func (e *Error) SQL() string {
9099

91100
// Error implements the error interface.
92101
func (e ErrorCode) Error() string {
93-
return util.ErrorCodeString(uint32(e))
102+
return util.ErrorCodeString(e)
103+
}
104+
105+
// As converts this error to an [ExtendedErrorCode].
106+
func (e ErrorCode) As(err any) bool {
107+
c, ok := err.(*xErrorCode)
108+
if ok {
109+
*c = xErrorCode(e)
110+
}
111+
return ok
94112
}
95113

96114
// Temporary returns true for [BUSY] errors.
@@ -105,7 +123,7 @@ func (e ErrorCode) ExtendedCode() ExtendedErrorCode {
105123

106124
// Error implements the error interface.
107125
func (e ExtendedErrorCode) Error() string {
108-
return util.ErrorCodeString(uint32(e))
126+
return util.ErrorCodeString(e)
109127
}
110128

111129
// Is tests whether this error matches a given [ErrorCode].
@@ -150,14 +168,10 @@ func errorCode(err error, def ErrorCode) (msg string, code res_t) {
150168
return code.msg, res_t(code.code)
151169
}
152170

153-
var ecode ErrorCode
154171
var xcode xErrorCode
155-
switch {
156-
case errors.As(err, &xcode):
172+
if errors.As(err, &xcode) {
157173
code = res_t(xcode)
158-
case errors.As(err, &ecode):
159-
code = res_t(ecode)
160-
default:
174+
} else {
161175
code = res_t(def)
162176
}
163177
return err.Error(), code

internal/util/error.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,20 @@ func AssertErr() ErrorString {
3333
return ErrorString(msg)
3434
}
3535

36-
func ErrorCodeString(rc uint32) string {
37-
switch rc {
36+
type errorCode interface {
37+
~uint8 | ~uint16 | ~uint32 | ~int32
38+
}
39+
40+
func ErrorCodeString[T errorCode](rc T) string {
41+
switch uint32(rc) {
3842
case ABORT_ROLLBACK:
3943
return "sqlite3: abort due to ROLLBACK"
4044
case ROW:
4145
return "sqlite3: another row available"
4246
case DONE:
4347
return "sqlite3: no more rows available"
4448
}
45-
switch rc & 0xff {
49+
switch uint8(rc) {
4650
case OK:
4751
return "sqlite3: not an error"
4852
case ERROR:

internal/util/module.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ type ConnKey struct{}
1212

1313
type moduleKey struct{}
1414
type moduleState struct {
15+
sysError error
1516
mmapState
1617
handleState
1718
}
@@ -23,3 +24,15 @@ func NewContext(ctx context.Context) context.Context {
2324
ctx = context.WithValue(ctx, moduleKey{}, state)
2425
return ctx
2526
}
27+
28+
func GetSystemError(ctx context.Context) error {
29+
s := ctx.Value(moduleKey{}).(*moduleState)
30+
return s.sysError
31+
}
32+
33+
func SetSystemError(ctx context.Context, err error) {
34+
s, ok := ctx.Value(moduleKey{}).(*moduleState)
35+
if ok {
36+
s.sysError = err
37+
}
38+
}

sqlite.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -125,14 +125,15 @@ func (sqlt *sqlite) error(rc res_t, handle ptr_t, sql ...string) error {
125125
panic(util.OOMErr)
126126
}
127127

128+
var msg, query string
128129
if handle != 0 {
129-
var msg, query string
130130
if ptr := ptr_t(sqlt.call("sqlite3_errmsg", stk_t(handle))); ptr != 0 {
131131
msg = util.ReadString(sqlt.mod, ptr, _MAX_LENGTH)
132+
msg = strings.TrimPrefix(msg, "sqlite3: ")
133+
msg = strings.TrimPrefix(msg, util.ErrorCodeString(rc)[len("sqlite3: "):])
134+
msg = strings.TrimPrefix(msg, ": ")
132135
if msg == "not an error" {
133136
msg = ""
134-
} else {
135-
msg = strings.TrimPrefix(msg, util.ErrorCodeString(uint32(rc))[len("sqlite3: "):])
136137
}
137138
}
138139

@@ -141,10 +142,16 @@ func (sqlt *sqlite) error(rc res_t, handle ptr_t, sql ...string) error {
141142
query = sql[0][i:]
142143
}
143144
}
145+
}
144146

145-
if msg != "" || query != "" {
146-
return &Error{code: rc, msg: msg, sql: query}
147-
}
147+
var sys error
148+
switch ErrorCode(rc) {
149+
case CANTOPEN, IOERR:
150+
sys = util.GetSystemError(sqlt.ctx)
151+
}
152+
153+
if sys != nil || msg != "" || query != "" {
154+
return &Error{code: rc, sys: sys, msg: msg, sql: query}
148155
}
149156
return xErrorCode(rc)
150157
}

tests/conn_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ func TestConn_Open_dir(t *testing.T) {
2222
if err == nil {
2323
t.Fatal("want error")
2424
}
25-
if !errors.Is(err, sqlite3.CANTOPEN) {
26-
t.Errorf("got %v, want sqlite3.CANTOPEN", err)
25+
if !errors.Is(err, sqlite3.CANTOPEN_ISDIR) {
26+
t.Errorf("got %v, want sqlite3.CANTOPEN_ISDIR", err)
2727
}
2828
}
2929

vfs/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ to check if your build supports shared memory.
7373

7474
### Blocking Locks
7575

76-
On Windows and macOS, this package implements
76+
On macOS, this package implements
7777
[Wal-mode blocking locks](https://sqlite.org/src/doc/tip/doc/wal-lock.md).
7878

7979
### Batch-Atomic Write

vfs/api.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,8 @@ type FileSharedMemory interface {
193193
// SharedMemory is a shared-memory WAL-index implementation.
194194
// Use [NewSharedMemory] to create a shared-memory.
195195
type SharedMemory interface {
196-
shmMap(context.Context, api.Module, int32, int32, bool) (ptr_t, _ErrorCode)
197-
shmLock(int32, int32, _ShmFlag) _ErrorCode
196+
shmMap(context.Context, api.Module, int32, int32, bool) (ptr_t, error)
197+
shmLock(int32, int32, _ShmFlag) error
198198
shmUnmap(bool)
199199
shmBarrier()
200200
io.Closer

0 commit comments

Comments
 (0)