From 281b921e141d2fc6eb1b7e09862fc10549297f17 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Mar 2025 06:53:05 +0000 Subject: [PATCH] [chore]: Bump github.com/ncruces/go-sqlite3 from 0.24.0 to 0.24.1 Bumps [github.com/ncruces/go-sqlite3](https://github.com/ncruces/go-sqlite3) from 0.24.0 to 0.24.1. - [Release notes](https://github.com/ncruces/go-sqlite3/releases) - [Commits](https://github.com/ncruces/go-sqlite3/compare/v0.24.0...v0.24.1) --- updated-dependencies: - dependency-name: github.com/ncruces/go-sqlite3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 4 +- go.sum | 4 +- .../github.com/ncruces/go-sqlite3/README.md | 22 ++- .../github.com/ncruces/go-sqlite3/config.go | 10 ++ vendor/github.com/ncruces/go-sqlite3/conn.go | 5 +- vendor/github.com/ncruces/go-sqlite3/const.go | 7 +- vendor/github.com/ncruces/go-sqlite3/func.go | 159 +++++++++++++----- .../ncruces/go-sqlite3/vfs/README.md | 35 ++-- .../github.com/ncruces/go-sqlite3/vfs/file.go | 4 +- .../ncruces/go-sqlite3/vfs/os_bsd.go | 27 ++- .../ncruces/go-sqlite3/vfs/os_darwin.go | 22 ++- .../ncruces/go-sqlite3/vfs/os_linux.go | 42 ++++- .../ncruces/go-sqlite3/vfs/os_unix.go | 11 +- .../ncruces/go-sqlite3/vfs/shm_bsd.go | 15 +- vendor/github.com/ncruces/go-sqlite3/vtab.go | 22 ++- vendor/modules.txt | 2 +- 16 files changed, 281 insertions(+), 110 deletions(-) diff --git a/go.mod b/go.mod index ca64fae33..0a9479f76 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module github.com/superseriousbusiness/gotosocial go 1.23.0 -toolchain go1.23.3 +toolchain go1.24.1 // Replace go-swagger with our version that fixes (ours particularly) use of Go1.23 replace github.com/go-swagger/go-swagger => codeberg.org/superseriousbusiness/go-swagger v0.31.0-gts-go1.23-fix @@ -53,7 +53,7 @@ require ( github.com/miekg/dns v1.1.63 github.com/minio/minio-go/v7 v7.0.85 github.com/mitchellh/mapstructure v1.5.0 - github.com/ncruces/go-sqlite3 v0.24.0 + github.com/ncruces/go-sqlite3 v0.24.1 github.com/oklog/ulid v1.3.1 github.com/prometheus/client_golang v1.21.1 github.com/rivo/uniseg v0.4.7 diff --git a/go.sum b/go.sum index c7af9162d..e947a5d3d 100644 --- a/go.sum +++ b/go.sum @@ -323,8 +323,8 @@ github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/ncruces/go-sqlite3 v0.24.0 h1:Z4jfmzu2NCd4SmyFwLT2OmF3EnTZbqwATvdiuNHNhLA= -github.com/ncruces/go-sqlite3 v0.24.0/go.mod h1:/Vs8ACZHjJ1SA6E9RZUn3EyB1OP3nDQ4z/ar+0fplTQ= +github.com/ncruces/go-sqlite3 v0.24.1 h1:qHlIz+dlH3Y0wCUErFZXon5hCvw1Kc9eEkZVYYi8p14= +github.com/ncruces/go-sqlite3 v0.24.1/go.mod h1:n6Z7036yFilJx04yV0mi5JWaF66rUmXn1It9Ux8dx68= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M= diff --git a/vendor/github.com/ncruces/go-sqlite3/README.md b/vendor/github.com/ncruces/go-sqlite3/README.md index cac6ee6b8..94fd9950b 100644 --- a/vendor/github.com/ncruces/go-sqlite3/README.md +++ b/vendor/github.com/ncruces/go-sqlite3/README.md @@ -65,17 +65,20 @@ db.QueryRow(`SELECT sqlite_version()`).Scan(&version) This module replaces the SQLite [OS Interface](https://sqlite.org/vfs.html) (aka VFS) with a [pure Go](vfs/) implementation, which has advantages and disadvantages. - Read more about the Go VFS design [here](vfs/README.md). +Because each database connection executes within a Wasm sandboxed environment, +memory usage will be higher than alternatives. + ### Testing This project aims for [high test coverage](https://github.com/ncruces/go-sqlite3/wiki/Test-coverage-report). It also benefits greatly from [SQLite's](https://sqlite.org/testing.html) and -[wazero's](https://tetrate.io/blog/introducing-wazero-from-tetrate/#:~:text=Rock%2Dsolid%20test%20approach) thorough testing. +[wazero's](https://tetrate.io/blog/introducing-wazero-from-tetrate/#:~:text=Rock%2Dsolid%20test%20approach) +thorough testing. Every commit is [tested](https://github.com/ncruces/go-sqlite3/wiki/Support-matrix) on -Linux (amd64/arm64/386/riscv64/ppc64le/s390x), macOS (amd64/arm64), +Linux (amd64/arm64/386/riscv64/ppc64le/s390x), macOS (arm64/amd64), Windows (amd64), FreeBSD (amd64/arm64), OpenBSD (amd64), NetBSD (amd64/arm64), DragonFly BSD (amd64), illumos (amd64), and Solaris (amd64). @@ -84,12 +87,21 @@ The Go VFS is tested by running SQLite's ### Performance -Perfomance of the [`database/sql`](https://pkg.go.dev/database/sql) driver is +Performance of the [`database/sql`](https://pkg.go.dev/database/sql) driver is [competitive](https://github.com/cvilsmeier/go-sqlite-bench) with alternatives. -The Wasm and VFS layers are also tested by running SQLite's +The Wasm and VFS layers are also benchmarked by running SQLite's [speedtest1](https://github.com/sqlite/sqlite/blob/master/test/speedtest1.c). +### Concurrency + +This module behaves similarly to SQLite in [multi-thread](https://sqlite.org/threadsafe.html) mode: +it is goroutine-safe, provided that no single database connection, or object derived from it, +is used concurrently by multiple goroutines. + +The [`database/sql`](https://pkg.go.dev/database/sql) API is safe to use concurrently, +according to its documentation. + ### FAQ, issues, new features For questions, please see [Discussions](https://github.com/ncruces/go-sqlite3/discussions/categories/q-a). diff --git a/vendor/github.com/ncruces/go-sqlite3/config.go b/vendor/github.com/ncruces/go-sqlite3/config.go index 17166b9c5..d9ce9f55f 100644 --- a/vendor/github.com/ncruces/go-sqlite3/config.go +++ b/vendor/github.com/ncruces/go-sqlite3/config.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "strconv" + "sync/atomic" "github.com/tetratelabs/wazero/api" @@ -48,6 +49,15 @@ func (c *Conn) Config(op DBConfig, arg ...bool) (bool, error) { return util.ReadBool(c.mod, argsPtr), c.error(rc) } +var defaultLogger atomic.Pointer[func(code ExtendedErrorCode, msg string)] + +// ConfigLog sets up the default error logging callback for new connections. +// +// https://sqlite.org/errlog.html +func ConfigLog(cb func(code ExtendedErrorCode, msg string)) { + defaultLogger.Store(&cb) +} + // ConfigLog sets up the error logging callback for the connection. // // https://sqlite.org/errlog.html diff --git a/vendor/github.com/ncruces/go-sqlite3/conn.go b/vendor/github.com/ncruces/go-sqlite3/conn.go index 9f9251e9f..044795c61 100644 --- a/vendor/github.com/ncruces/go-sqlite3/conn.go +++ b/vendor/github.com/ncruces/go-sqlite3/conn.go @@ -49,7 +49,7 @@ func Open(filename string) (*Conn, error) { } // OpenContext is like [Open] but includes a context, -// which is used to interrupt the process of opening the connectiton. +// which is used to interrupt the process of opening the connection. func OpenContext(ctx context.Context, filename string) (*Conn, error) { return newConn(ctx, filename, OPEN_READWRITE|OPEN_CREATE|OPEN_URI) } @@ -92,6 +92,9 @@ func newConn(ctx context.Context, filename string, flags OpenFlag) (ret *Conn, _ }() c.ctx = context.WithValue(c.ctx, connKey{}, c) + if logger := defaultLogger.Load(); logger != nil { + c.ConfigLog(*logger) + } c.arena = c.newArena() c.handle, err = c.openDB(filename, flags) if err == nil { diff --git a/vendor/github.com/ncruces/go-sqlite3/const.go b/vendor/github.com/ncruces/go-sqlite3/const.go index 82d80515e..522f68bfb 100644 --- a/vendor/github.com/ncruces/go-sqlite3/const.go +++ b/vendor/github.com/ncruces/go-sqlite3/const.go @@ -11,10 +11,9 @@ const ( _ROW = 100 /* sqlite3_step() has another row ready */ _DONE = 101 /* sqlite3_step() has finished executing */ - _MAX_NAME = 1e6 // Self-imposed limit for most NUL terminated strings. - _MAX_LENGTH = 1e9 - _MAX_SQL_LENGTH = 1e9 - _MAX_FUNCTION_ARG = 100 + _MAX_NAME = 1e6 // Self-imposed limit for most NUL terminated strings. + _MAX_LENGTH = 1e9 + _MAX_SQL_LENGTH = 1e9 ptrlen = util.PtrLen intlen = util.IntLen diff --git a/vendor/github.com/ncruces/go-sqlite3/func.go b/vendor/github.com/ncruces/go-sqlite3/func.go index f907fa940..934a5c13e 100644 --- a/vendor/github.com/ncruces/go-sqlite3/func.go +++ b/vendor/github.com/ncruces/go-sqlite3/func.go @@ -3,7 +3,9 @@ package sqlite3 import ( "context" "io" + "iter" "sync" + "sync/atomic" "github.com/tetratelabs/wazero/api" @@ -45,7 +47,7 @@ func (c Conn) AnyCollationNeeded() error { // CreateCollation defines a new collating sequence. // // https://sqlite.org/c3ref/create_collation.html -func (c *Conn) CreateCollation(name string, fn func(a, b []byte) int) error { +func (c *Conn) CreateCollation(name string, fn CollatingFunction) error { var funcPtr ptr_t defer c.arena.mark()() namePtr := c.arena.string(name) @@ -57,6 +59,10 @@ func (c *Conn) CreateCollation(name string, fn func(a, b []byte) int) error { return c.error(rc) } +// Collating function is the type of a collation callback. +// Implementations must not retain a or b. +type CollatingFunction func(a, b []byte) int + // CreateFunction defines a new scalar SQL function. // // https://sqlite.org/c3ref/create_function.html @@ -77,34 +83,67 @@ func (c *Conn) CreateFunction(name string, nArg int, flag FunctionFlag, fn Scala // Implementations must not retain arg. type ScalarFunction func(ctx Context, arg ...Value) -// CreateWindowFunction defines a new aggregate or aggregate window SQL function. -// If fn returns a [WindowFunction], then an aggregate window function is created. -// If fn returns an [io.Closer], it will be called to free resources. +// CreateAggregateFunction defines a new aggregate SQL function. // // https://sqlite.org/c3ref/create_function.html -func (c *Conn) CreateWindowFunction(name string, nArg int, flag FunctionFlag, fn func() AggregateFunction) error { +func (c *Conn) CreateAggregateFunction(name string, nArg int, flag FunctionFlag, fn AggregateSeqFunction) error { var funcPtr ptr_t defer c.arena.mark()() namePtr := c.arena.string(name) - call := "sqlite3_create_aggregate_function_go" if fn != nil { - agg := fn() - if c, ok := agg.(io.Closer); ok { - if err := c.Close(); err != nil { - return err + funcPtr = util.AddHandle(c.ctx, AggregateConstructor(func() AggregateFunction { + var a aggregateFunc + coro := func(yieldCoro func(struct{}) bool) { + seq := func(yieldSeq func([]Value) bool) { + for yieldSeq(a.arg) { + if !yieldCoro(struct{}{}) { + break + } + } + } + fn(&a.ctx, seq) } - } - if _, ok := agg.(WindowFunction); ok { - call = "sqlite3_create_window_function_go" - } - funcPtr = util.AddHandle(c.ctx, fn) + a.next, a.stop = iter.Pull(coro) + return &a + })) } - rc := res_t(c.call(call, + rc := res_t(c.call("sqlite3_create_aggregate_function_go", stk_t(c.handle), stk_t(namePtr), stk_t(nArg), stk_t(flag), stk_t(funcPtr))) return c.error(rc) } +// AggregateSeqFunction is the type of an aggregate SQL function. +// Implementations must not retain the slices yielded by seq. +type AggregateSeqFunction func(ctx *Context, seq iter.Seq[[]Value]) + +// CreateWindowFunction defines a new aggregate or aggregate window SQL function. +// If fn returns a [WindowFunction], an aggregate window function is created. +// If fn returns an [io.Closer], it will be called to free resources. +// +// https://sqlite.org/c3ref/create_function.html +func (c *Conn) CreateWindowFunction(name string, nArg int, flag FunctionFlag, fn AggregateConstructor) error { + var funcPtr ptr_t + defer c.arena.mark()() + namePtr := c.arena.string(name) + if fn != nil { + funcPtr = util.AddHandle(c.ctx, AggregateConstructor(func() AggregateFunction { + agg := fn() + if win, ok := agg.(WindowFunction); ok { + return win + } + return windowFunc{agg, name} + })) + } + rc := res_t(c.call("sqlite3_create_window_function_go", + stk_t(c.handle), stk_t(namePtr), stk_t(nArg), + stk_t(flag), stk_t(funcPtr))) + return c.error(rc) +} + +// AggregateConstructor is a an [AggregateFunction] constructor. +type AggregateConstructor func() AggregateFunction + // AggregateFunction is the interface an aggregate function should implement. // // https://sqlite.org/appfunc.html @@ -153,26 +192,24 @@ func collationCallback(ctx context.Context, mod api.Module, pArg, pDB ptr_t, eTe } func compareCallback(ctx context.Context, mod api.Module, pApp ptr_t, nKey1 int32, pKey1 ptr_t, nKey2 int32, pKey2 ptr_t) uint32 { - fn := util.GetHandle(ctx, pApp).(func(a, b []byte) int) + fn := util.GetHandle(ctx, pApp).(CollatingFunction) return uint32(fn(util.View(mod, pKey1, int64(nKey1)), util.View(mod, pKey2, int64(nKey2)))) } func funcCallback(ctx context.Context, mod api.Module, pCtx, pApp ptr_t, nArg int32, pArg ptr_t) { - args := getFuncArgs() - defer putFuncArgs(args) db := ctx.Value(connKey{}).(*Conn) + args := callbackArgs(db, nArg, pArg) + defer returnArgs(args) fn := util.GetHandle(db.ctx, pApp).(ScalarFunction) - callbackArgs(db, args[:nArg], pArg) - fn(Context{db, pCtx}, args[:nArg]...) + fn(Context{db, pCtx}, *args...) } func stepCallback(ctx context.Context, mod api.Module, pCtx, pAgg, pApp ptr_t, nArg int32, pArg ptr_t) { - args := getFuncArgs() - defer putFuncArgs(args) db := ctx.Value(connKey{}).(*Conn) - callbackArgs(db, args[:nArg], pArg) + args := callbackArgs(db, nArg, pArg) + defer returnArgs(args) fn, _ := callbackAggregate(db, pAgg, pApp) - fn.Step(Context{db, pCtx}, args[:nArg]...) + fn.Step(Context{db, pCtx}, *args...) } func valueCallback(ctx context.Context, mod api.Module, pCtx, pAgg, pApp ptr_t, final int32) { @@ -196,12 +233,11 @@ func valueCallback(ctx context.Context, mod api.Module, pCtx, pAgg, pApp ptr_t, } func inverseCallback(ctx context.Context, mod api.Module, pCtx, pAgg ptr_t, nArg int32, pArg ptr_t) { - args := getFuncArgs() - defer putFuncArgs(args) db := ctx.Value(connKey{}).(*Conn) - callbackArgs(db, args[:nArg], pArg) + args := callbackArgs(db, nArg, pArg) + defer returnArgs(args) fn := util.GetHandle(db.ctx, pAgg).(WindowFunction) - fn.Inverse(Context{db, pCtx}, args[:nArg]...) + fn.Inverse(Context{db, pCtx}, *args...) } func callbackAggregate(db *Conn, pAgg, pApp ptr_t) (AggregateFunction, ptr_t) { @@ -211,7 +247,7 @@ func callbackAggregate(db *Conn, pAgg, pApp ptr_t) (AggregateFunction, ptr_t) { } // We need to create the aggregate. - fn := util.GetHandle(db.ctx, pApp).(func() AggregateFunction)() + fn := util.GetHandle(db.ctx, pApp).(AggregateConstructor)() if pAgg != 0 { handle := util.AddHandle(db.ctx, fn) util.Write32(db.mod, pAgg, handle) @@ -220,25 +256,64 @@ func callbackAggregate(db *Conn, pAgg, pApp ptr_t) (AggregateFunction, ptr_t) { return fn, 0 } -func callbackArgs(db *Conn, arg []Value, pArg ptr_t) { - for i := range arg { - arg[i] = Value{ +var ( + valueArgsPool sync.Pool + valueArgsLen atomic.Int32 +) + +func callbackArgs(db *Conn, nArg int32, pArg ptr_t) *[]Value { + arg, ok := valueArgsPool.Get().(*[]Value) + if !ok || cap(*arg) < int(nArg) { + max := valueArgsLen.Or(nArg) | nArg + lst := make([]Value, max) + arg = &lst + } + lst := (*arg)[:nArg] + for i := range lst { + lst[i] = Value{ c: db, handle: util.Read32[ptr_t](db.mod, pArg+ptr_t(i)*ptrlen), } } + *arg = lst + return arg } -var funcArgsPool sync.Pool - -func putFuncArgs(p *[_MAX_FUNCTION_ARG]Value) { - funcArgsPool.Put(p) +func returnArgs(p *[]Value) { + valueArgsPool.Put(p) } -func getFuncArgs() *[_MAX_FUNCTION_ARG]Value { - if p := funcArgsPool.Get(); p == nil { - return new([_MAX_FUNCTION_ARG]Value) - } else { - return p.(*[_MAX_FUNCTION_ARG]Value) +type aggregateFunc struct { + ctx Context + arg []Value + next func() (struct{}, bool) + stop func() +} + +func (a *aggregateFunc) Step(ctx Context, arg ...Value) { + a.ctx = ctx + a.arg = append(a.arg[:0], arg...) + if _, more := a.next(); !more { + a.stop() } } + +func (a *aggregateFunc) Value(ctx Context) { + a.ctx = ctx + a.stop() +} + +func (a *aggregateFunc) Close() error { + a.stop() + return nil +} + +type windowFunc struct { + AggregateFunction + name string +} + +func (w windowFunc) Inverse(ctx Context, arg ...Value) { + // Implementing inverse allows certain queries that don't really need it to succeed. + ctx.ResultError(util.ErrorString(w.name + ": may not be used as a window function")) +} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/README.md b/vendor/github.com/ncruces/go-sqlite3/vfs/README.md index 4e987ce3f..17c24ec65 100644 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/README.md +++ b/vendor/github.com/ncruces/go-sqlite3/vfs/README.md @@ -6,22 +6,30 @@ It replaces the default SQLite VFS with a **pure Go** implementation, and exposes [interfaces](https://pkg.go.dev/github.com/ncruces/go-sqlite3/vfs#VFS) that should allow you to implement your own [custom VFSes](#custom-vfses). -Since it is a from scratch reimplementation, -there are naturally some ways it deviates from the original. +See the [support matrix](https://github.com/ncruces/go-sqlite3/wiki/Support-matrix) +for the list of supported OS and CPU architectures. -The main differences are [file locking](#file-locking) and [WAL mode](#write-ahead-logging) support. +Since this is a from scratch reimplementation, +there are naturally some ways it deviates from the original. +It's also not as battle tested as the original. + +The main differences to be aware of are +[file locking](#file-locking) and +[WAL mode](#write-ahead-logging) support. ### File Locking -POSIX advisory locks, which SQLite uses on Unix, are -[broken by design](https://github.com/sqlite/sqlite/blob/b74eb0/src/os_unix.c#L1073-L1161). +POSIX advisory locks, +which SQLite uses on [Unix](https://github.com/sqlite/sqlite/blob/5d60f4/src/os_unix.c#L13-L14), +are [broken by design](https://github.com/sqlite/sqlite/blob/5d60f4/src/os_unix.c#L1074-L1162). Instead, on Linux and macOS, this package uses [OFD locks](https://www.gnu.org/software/libc/manual/html_node/Open-File-Description-Locks.html) to synchronize access to database files. This package can also use [BSD locks](https://man.freebsd.org/cgi/man.cgi?query=flock&sektion=2), -albeit with reduced concurrency (`BEGIN IMMEDIATE` behaves like `BEGIN EXCLUSIVE`). +albeit with reduced concurrency (`BEGIN IMMEDIATE` behaves like `BEGIN EXCLUSIVE`, +[docs](https://sqlite.org/lang_transaction.html#immediate)). BSD locks are the default on BSD and illumos, but you can opt into them with the `sqlite3_flock` build tag. @@ -44,11 +52,11 @@ to check if your build supports file locking. ### Write-Ahead Logging -On Unix, this package may use `mmap` to implement +On Unix, this package uses `mmap` to implement [shared-memory for the WAL-index](https://sqlite.org/wal.html#implementation_of_shared_memory_for_the_wal_index), like SQLite. -On Windows, this package may use `MapViewOfFile`, like SQLite. +On Windows, this package uses `MapViewOfFile`, like SQLite. You can also opt into a cross-platform, in-process, memory sharing implementation with the `sqlite3_dotlk` build tag. @@ -63,6 +71,11 @@ you must disable connection pooling by calling You can use [`vfs.SupportsSharedMemory`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/vfs#SupportsSharedMemory) to check if your build supports shared memory. +### Blocking Locks + +On Windows and macOS, this package implements +[Wal-mode blocking locks](https://sqlite.org/src/doc/tip/doc/wal-lock.md). + ### Batch-Atomic Write On Linux, this package may support @@ -94,8 +107,10 @@ The VFS can be customized with a few build tags: > [`unix-flock` VFS](https://sqlite.org/compile.html#enable_locking_style); > `sqlite3_dotlk` builds are compatible with the > [`unix-dotfile` VFS](https://sqlite.org/compile.html#enable_locking_style). -> If incompatible file locking is used, accessing databases concurrently with -> _other_ SQLite libraries will eventually corrupt data. + +> [!CAUTION] +> Concurrently accessing databases using incompatible VFSes +> will eventually corrupt data. ### Custom VFSes diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/file.go b/vendor/github.com/ncruces/go-sqlite3/vfs/file.go index 0a3c9d622..6f8ccc66b 100644 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/file.go +++ b/vendor/github.com/ncruces/go-sqlite3/vfs/file.go @@ -125,6 +125,7 @@ func (vfsOS) OpenFilename(name *Filename, flags OpenFlag) (File, OpenFlag, error file := vfsFile{ File: f, psow: true, + atomic: osBatchAtomic(f), readOnly: flags&OPEN_READONLY != 0, syncDir: canSyncDirs && isCreate && isJournl, shm: NewSharedMemory(name.String()+"-shm", flags), @@ -139,6 +140,7 @@ type vfsFile struct { readOnly bool keepWAL bool syncDir bool + atomic bool psow bool } @@ -200,7 +202,7 @@ func (f *vfsFile) SectorSize() int { func (f *vfsFile) DeviceCharacteristics() DeviceCharacteristic { ret := IOCAP_SUBPAGE_READ - if osBatchAtomic(f.File) { + if f.atomic { ret |= IOCAP_BATCH_ATOMIC } if f.psow { diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/os_bsd.go b/vendor/github.com/ncruces/go-sqlite3/vfs/os_bsd.go index 4f6fadef4..4542f8e7c 100644 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/os_bsd.go +++ b/vendor/github.com/ncruces/go-sqlite3/vfs/os_bsd.go @@ -50,11 +50,15 @@ func osDowngradeLock(file *os.File, _ LockLevel) _ErrorCode { } func osReleaseLock(file *os.File, _ LockLevel) _ErrorCode { - err := unix.Flock(int(file.Fd()), unix.LOCK_UN) - if err != nil { - return _IOERR_UNLOCK + for { + err := unix.Flock(int(file.Fd()), unix.LOCK_UN) + if err == nil { + return _OK + } + if err != unix.EINTR { + return _IOERR_UNLOCK + } } - return _OK } func osCheckReservedLock(file *os.File) (bool, _ErrorCode) { @@ -89,13 +93,18 @@ func osLock(file *os.File, typ int16, start, len int64, def _ErrorCode) _ErrorCo } func osUnlock(file *os.File, start, len int64) _ErrorCode { - err := unix.FcntlFlock(file.Fd(), unix.F_SETLK, &unix.Flock_t{ + lock := unix.Flock_t{ Type: unix.F_UNLCK, Start: start, Len: len, - }) - if err != nil { - return _IOERR_UNLOCK } - return _OK + for { + err := unix.FcntlFlock(file.Fd(), unix.F_SETLK, &lock) + if err == nil { + return _OK + } + if err != unix.EINTR { + return _IOERR_UNLOCK + } + } } diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/os_darwin.go b/vendor/github.com/ncruces/go-sqlite3/vfs/os_darwin.go index 07de7c3d8..ee08e9a7b 100644 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/os_darwin.go +++ b/vendor/github.com/ncruces/go-sqlite3/vfs/os_darwin.go @@ -27,7 +27,12 @@ func osSync(file *os.File, fullsync, _ /*dataonly*/ bool) error { if fullsync { return file.Sync() } - return unix.Fsync(int(file.Fd())) + for { + err := unix.Fsync(int(file.Fd())) + if err != unix.EINTR { + return err + } + } } func osAllocate(file *os.File, size int64) error { @@ -85,13 +90,18 @@ func osLock(file *os.File, typ int16, start, len int64, timeout time.Duration, d } func osUnlock(file *os.File, start, len int64) _ErrorCode { - err := unix.FcntlFlock(file.Fd(), _F_OFD_SETLK, &unix.Flock_t{ + lock := unix.Flock_t{ Type: unix.F_UNLCK, Start: start, Len: len, - }) - if err != nil { - return _IOERR_UNLOCK } - return _OK + for { + err := unix.FcntlFlock(file.Fd(), _F_OFD_SETLK, &lock) + if err == nil { + return _OK + } + if err != unix.EINTR { + return _IOERR_UNLOCK + } + } } diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/os_linux.go b/vendor/github.com/ncruces/go-sqlite3/vfs/os_linux.go index 6199c7b00..be05f4b51 100644 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/os_linux.go +++ b/vendor/github.com/ncruces/go-sqlite3/vfs/os_linux.go @@ -3,6 +3,7 @@ package vfs import ( + "io" "os" "time" @@ -11,14 +12,36 @@ import ( func osSync(file *os.File, _ /*fullsync*/, _ /*dataonly*/ bool) error { // SQLite trusts Linux's fdatasync for all fsync's. - return unix.Fdatasync(int(file.Fd())) + for { + err := unix.Fdatasync(int(file.Fd())) + if err != unix.EINTR { + return err + } + } } func osAllocate(file *os.File, size int64) error { if size == 0 { return nil } - return unix.Fallocate(int(file.Fd()), 0, 0, size) + for { + err := unix.Fallocate(int(file.Fd()), 0, 0, size) + if err == unix.EOPNOTSUPP { + break + } + if err != unix.EINTR { + return err + } + } + off, err := file.Seek(0, io.SeekEnd) + if err != nil { + return err + } + if size <= off { + return nil + } + return file.Truncate(size) + } func osReadLock(file *os.File, start, len int64, timeout time.Duration) _ErrorCode { @@ -46,13 +69,18 @@ func osLock(file *os.File, typ int16, start, len int64, timeout time.Duration, d } func osUnlock(file *os.File, start, len int64) _ErrorCode { - err := unix.FcntlFlock(file.Fd(), unix.F_OFD_SETLK, &unix.Flock_t{ + lock := unix.Flock_t{ Type: unix.F_UNLCK, Start: start, Len: len, - }) - if err != nil { - return _IOERR_UNLOCK } - return _OK + for { + err := unix.FcntlFlock(file.Fd(), unix.F_OFD_SETLK, &lock) + if err == nil { + return _OK + } + if err != unix.EINTR { + return _IOERR_UNLOCK + } + } } diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/os_unix.go b/vendor/github.com/ncruces/go-sqlite3/vfs/os_unix.go index 9f42b5f6c..3222ac79b 100644 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/os_unix.go +++ b/vendor/github.com/ncruces/go-sqlite3/vfs/os_unix.go @@ -65,10 +65,15 @@ func osTestLock(file *os.File, start, len int64) (int16, _ErrorCode) { Start: start, Len: len, } - if unix.FcntlFlock(file.Fd(), unix.F_GETLK, &lock) != nil { - return 0, _IOERR_CHECKRESERVEDLOCK + for { + err := unix.FcntlFlock(file.Fd(), unix.F_GETLK, &lock) + if err == nil { + return lock.Type, _OK + } + if err != unix.EINTR { + return 0, _IOERR_CHECKRESERVEDLOCK + } } - return lock.Type, _OK } func osLockErrorCode(err error, def _ErrorCode) _ErrorCode { diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/shm_bsd.go b/vendor/github.com/ncruces/go-sqlite3/vfs/shm_bsd.go index 11e7bb2fd..be1495d99 100644 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/shm_bsd.go +++ b/vendor/github.com/ncruces/go-sqlite3/vfs/shm_bsd.go @@ -68,16 +68,11 @@ func (s *vfsShm) Close() error { panic(util.AssertErr()) } -func (s *vfsShm) shmOpen() _ErrorCode { +func (s *vfsShm) shmOpen() (rc _ErrorCode) { if s.vfsShmParent != nil { return _OK } - var f *os.File - // Close file on error. - // Keep this here to avoid confusing checklocks. - defer func() { f.Close() }() - vfsShmListMtx.Lock() defer vfsShmListMtx.Unlock() @@ -98,11 +93,16 @@ func (s *vfsShm) shmOpen() _ErrorCode { } // Always open file read-write, as it will be shared. - f, err = os.OpenFile(s.path, + f, err := os.OpenFile(s.path, os.O_RDWR|os.O_CREATE|_O_NOFOLLOW, 0666) if err != nil { return _CANTOPEN } + defer func() { + if rc != _OK { + f.Close() + } + }() // Dead man's switch. if lock, rc := osTestLock(f, _SHM_DMS, 1); rc != _OK { @@ -131,7 +131,6 @@ func (s *vfsShm) shmOpen() _ErrorCode { File: f, info: fi, } - f = nil // Don't close the file. for i, g := range vfsShmList { if g == nil { vfsShmList[i] = s.vfsShmParent diff --git a/vendor/github.com/ncruces/go-sqlite3/vtab.go b/vendor/github.com/ncruces/go-sqlite3/vtab.go index 884aaaa0c..f4282d991 100644 --- a/vendor/github.com/ncruces/go-sqlite3/vtab.go +++ b/vendor/github.com/ncruces/go-sqlite3/vtab.go @@ -162,6 +162,7 @@ type VTabDestroyer interface { } // A VTabUpdater allows a virtual table to be updated. +// Implementations must not retain arg. type VTabUpdater interface { VTab // https://sqlite.org/vtab.html#xupdate @@ -241,6 +242,7 @@ type VTabSavepointer interface { // to loop through the virtual table. // A VTabCursor may optionally implement // [io.Closer] to free resources. +// Implementations of Filter must not retain arg. // // https://sqlite.org/c3ref/vtab_cursor.html type VTabCursor interface { @@ -489,12 +491,12 @@ func vtabBestIndexCallback(ctx context.Context, mod api.Module, pVTab, pIdxInfo } func vtabUpdateCallback(ctx context.Context, mod api.Module, pVTab ptr_t, nArg int32, pArg, pRowID ptr_t) res_t { - vtab := vtabGetHandle(ctx, mod, pVTab).(VTabUpdater) - db := ctx.Value(connKey{}).(*Conn) - args := make([]Value, nArg) - callbackArgs(db, args, pArg) - rowID, err := vtab.Update(args...) + args := callbackArgs(db, nArg, pArg) + defer returnArgs(args) + + vtab := vtabGetHandle(ctx, mod, pVTab).(VTabUpdater) + rowID, err := vtab.Update(*args...) if err == nil { util.Write64(mod, pRowID, rowID) } @@ -593,15 +595,17 @@ func cursorCloseCallback(ctx context.Context, mod api.Module, pCur 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 { - cursor := vtabGetHandle(ctx, mod, pCur).(VTabCursor) db := ctx.Value(connKey{}).(*Conn) - args := make([]Value, nArg) - callbackArgs(db, args, pArg) + args := callbackArgs(db, nArg, pArg) + defer returnArgs(args) + var idxName string if idxStr != 0 { idxName = util.ReadString(mod, idxStr, _MAX_LENGTH) } - err := cursor.Filter(int(idxNum), idxName, args...) + + cursor := vtabGetHandle(ctx, mod, pCur).(VTabCursor) + err := cursor.Filter(int(idxNum), idxName, *args...) return vtabError(ctx, mod, pCur, _CURSOR_ERROR, err) } diff --git a/vendor/modules.txt b/vendor/modules.txt index 4f5ca928e..76deb6a71 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -698,7 +698,7 @@ github.com/modern-go/reflect2 # github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 ## explicit github.com/munnerz/goautoneg -# github.com/ncruces/go-sqlite3 v0.24.0 +# github.com/ncruces/go-sqlite3 v0.24.1 ## explicit; go 1.23.0 github.com/ncruces/go-sqlite3 github.com/ncruces/go-sqlite3/driver