diff --git a/go.mod b/go.mod index 1bf6516..c0ceab5 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( golang.org/x/net v0.59.0 golang.org/x/oauth2 v0.37.0 golang.org/x/sys v0.48.0 - modernc.org/sqlite v1.58.0 + modernc.org/sqlite v1.59.0 ) require ( diff --git a/go.sum b/go.sum index 740856c..ca92a7a 100644 --- a/go.sum +++ b/go.sum @@ -192,8 +192,8 @@ modernc.org/opt v0.2.0 h1:tGyef5ApycA7FSEOMraay9SaTk5zmbx7Tu+cJs4QKZg= modernc.org/opt v0.2.0/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= -modernc.org/sqlite v1.58.0 h1:38u40/bwkfM7f0Myhosl+SEMltSDxnGdQf8o6Kjmys0= -modernc.org/sqlite v1.58.0/go.mod h1:rsD2CckafgObKC4DhBlGBf+RiHxkc3hINGt1Xw32tVY= +modernc.org/sqlite v1.59.0 h1:X1es1GpqBlS/5T+vbM4HLUdaa8OtQx468DF2vrx+38A= +modernc.org/sqlite v1.59.0/go.mod h1:+paeT2A3iPRHkQDwG7oA6Tk0zQd5woMEI8q7orfry8k= modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= diff --git a/vendor/github.com/klauspost/cpuid/v2/CONTRIBUTING.txt b/vendor/github.com/klauspost/cpuid/v2/CONTRIBUTING.txt index 452d28e..2ef4714 100644 --- a/vendor/github.com/klauspost/cpuid/v2/CONTRIBUTING.txt +++ b/vendor/github.com/klauspost/cpuid/v2/CONTRIBUTING.txt @@ -1,35 +1,35 @@ -Developer Certificate of Origin -Version 1.1 - -Copyright (C) 2015- Klaus Post & Contributors. -Email: klauspost@gmail.com - -Everyone is permitted to copy and distribute verbatim copies of this -license document, but changing it is not allowed. - - -Developer's Certificate of Origin 1.1 - -By making a contribution to this project, I certify that: - -(a) The contribution was created in whole or in part by me and I - have the right to submit it under the open source license - indicated in the file; or - -(b) The contribution is based upon previous work that, to the best - of my knowledge, is covered under an appropriate open source - license and I have the right under that license to submit that - work with modifications, whether created in whole or in part - by me, under the same open source license (unless I am - permitted to submit under a different license), as indicated - in the file; or - -(c) The contribution was provided directly to me by some other - person who certified (a), (b) or (c) and I have not modified - it. - -(d) I understand and agree that this project and the contribution - are public and that a record of the contribution (including all - personal information I submit with it, including my sign-off) is - maintained indefinitely and may be redistributed consistent with - this project or the open source license(s) involved. +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2015- Klaus Post & Contributors. +Email: klauspost@gmail.com + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. diff --git a/vendor/modernc.org/sqlite/AUTHORS b/vendor/modernc.org/sqlite/AUTHORS index 9149057..7006cbd 100644 --- a/vendor/modernc.org/sqlite/AUTHORS +++ b/vendor/modernc.org/sqlite/AUTHORS @@ -25,6 +25,7 @@ Logan Snow Michael Hoffmann Michael Rykov Morgan Bazalgette +Nathan Herring Ross Light SUSE LLC Saed SayedAhmed diff --git a/vendor/modernc.org/sqlite/CHANGELOG.md b/vendor/modernc.org/sqlite/CHANGELOG.md index bc9ad8b..5bade76 100644 --- a/vendor/modernc.org/sqlite/CHANGELOG.md +++ b/vendor/modernc.org/sqlite/CHANGELOG.md @@ -1,10 +1,19 @@ # Changelog +Entries for v1.38.1 through v1.44.1 and for v1.49.1 were added on 2026-09-05, reconstructed from the git history and the merge requests they cite; they were missing at release time. + + - 2026-09-15 v1.59.0: + - Bump the pinned `modernc.org/libc` to [v1.75.7](https://gitlab.com/cznic/libc/-/tags/v1.75.7) and re-vendor `lib/` and `vec/` from `modernc.org/libsqlite3` v1.14.5 and `modernc.org/libsqlite_vec` v0.5.0, which were transpiled against it. As always, downstream `go.mod` files must pin the same `modernc.org/libc` version as this repository's `go.mod`; see the package documentation and [GitLab issue #177](https://gitlab.com/cznic/sqlite/-/issues/177). The transpiled SQLite is unchanged: still 3.53.4, byte-identical to v1.58.0 on all 20 targets. The change is beneath it. On the Linux targets libc v1.75.7 replaces the transpiled musl `memcpy`, `memmove`, `memset`, `memcmp`, `strcspn` and `fabs`, loops moving at most four bytes per step, with native Go routines backed by the runtime's vectorized `memmove` and `memclr` and by the `bytes` package; on every target `strlen` is now a word-at-a-time scan, or `bytes.IndexByte` on the 64-bit architectures. On the three CPU-bound workloads in the new Performance section of the package documentation, measured on linux/amd64 against the same SQLite 3.53.4 compiled from C with the same options, this driver went from 3.0x, 2.2x and 1.6x the CPU time of the C build to 2.0x, 1.9x and 1.3x. The other operating systems already used a native Go `memcpy` and `memmove` and see no such change. `vec/` stays at sqlite-vec v0.1.9; its re-vendor, from a transpile made with newer modernc.org/cc and modernc.org/ccgo, differs only in unreferenced macro constants and in one bounds check spelled with `INT8_MAX` instead of its value, so nothing changes in behavior there either. + - Hand user-defined function and aggregate callbacks a pooled `*FunctionContext` instead of allocating a fresh one per call. After the `[]driver.Value` pooling of #226 this was the last driver-side heap allocation per invocation: one 16-byte object for every `Scalar`, `Step`, `WindowInverse`, `WindowValue` and `Final` call. The context now also carries the invocation's `sqlite3_context`, so accessor methods can be added to it later without touching the trampolines. Like the argument slice, it is valid only for the duration of the callback and must not be retained past its return; the documentation on `FunctionContext` and on the callbacks now says so. On the 1000-row, 3-argument noop scalar UDF benchmark this removes a further 1000 allocs/op (5756 to 4756, and 3756 to 2756 with `VolatileArgs`) and 16 KB/op; on the reporter's reproducer from #226 it removes about 12% of the remaining allocations (25.3M to 22.4M allocs/op, 553 MB to 505 MB per iteration). + - Updates [GitLab issue #226](https://gitlab.com/cznic/sqlite/-/issues/226). See [GitLab merge request #137](https://gitlab.com/cznic/sqlite/-/merge_requests/137). + - Add regression tests for the pooled context: two functions evaluated in one statement must receive two different `sqlite3_context` values and every callback's context must belong to the invoking connection, checked on two connections held at once and without dereferencing the context, so that a stale one is reported rather than faulted on; eight connections held at once calling a function from their own goroutines, and a function that runs a statement invoking another function, both meant for the race detector. See [GitLab merge request #138](https://gitlab.com/cznic/sqlite/-/merge_requests/138), thanks Ian Chechin! + - Add a Performance section to the package documentation. It records the measured CPU-time ratios of this driver against the same SQLite compiled from C, that they hold under concurrency, where the gap comes from, and the two consequences for applications: index the columns that `ORDER BY`, `GROUP BY` and `WHERE` use, because a query that is merely sluggish in C can cross a deadline here, and bound the `database/sql` pool with `SetMaxOpenConns`, because a periodic query that outlasts its period piles up connections without bound. Prompted by [a report](https://github.com/coderage-labs/spillway/issues/162) that attributed a 103 s query to the driver spilling a temporary b-tree in Go; the workload showed no spill and about 2x the CPU cost of C, the wall time being unbounded overlap of periodic polls. + - 2026-09-01 v1.58.0: - Upgrade to [SQLite 3.53.4](https://sqlite.org/releaselog/3_53_4.html). Upstream's own fix for the journal-rollback data-corruption bug is part of this release, so the local super-journal patch v1.56.0 introduced — and promised to drop once upstream shipped theirs — is dropped; recovery behavior is unchanged. This also bumps the pinned `modernc.org/libc` to v1.75.6; as always, downstream modules must pin the exact `modernc.org/libc` version this module's `go.mod` pins (see [GitLab issue #177](https://gitlab.com/cznic/sqlite/-/issues/177)). - Add opt-in support for **Linux Open File Description (OFD) locks** on database files. A POSIX record lock is owned by the (process, inode) pair, so the kernel drops every lock the process holds on a database file whenever any descriptor of that file is closed: an `os.Open`/`Close` for a hash, a backup check or a metadata probe anywhere in the process — third-party libraries included — silently strips SQLite's transaction locks and leaves the file unprotected against other processes. With OFD locking enabled, the locks belong to the open file description that placed them and survive such a close. **Off by default, and staying off until the mode has real-world mileage**: without opting in, locking behavior is byte-for-byte that of previous releases. Enable it by setting `MODERNC_SQLITE_OFD_LOCK=1` in the environment the process starts with (any value but the empty string or one starting with `0`; read once, at library initialization), or from Go with the new `OFDLocking(true)`, which overrides the variable and must run before the first connection is opened; `OFDLockingEnabled` reports the mode in effect. The switch is deliberately **process-wide rather than a DSN parameter**: POSIX and OFD locks taken by one process are different owners to the kernel and genuinely conflict, so every connection to a database file inside one process must use the same kind, and a per-DSN knob would advertise a granularity the kernel does not offer (see the discussion in #255). Because the two kinds do not release one another, the mode is frozen at the process's first lock attempt: later attempts to change it return the new `ErrOFDLockingTooLate`, while querying, and setting the value already in effect, keep working. On kernels older than 3.15, and on filesystems that reject OFD locks, the first lock attempt falls back to POSIX locks for good and `OFDLocking` returns the new `ErrOFDLockingUnavailable` from then on, which is also how `OFDLockingEnabled` turning false reports the fallback; the same error is returned on every platform but Linux, where the API exists but OFD locks do not. Two boundaries to note: the immunity covers the locks on the database file itself, while WAL's `-shm` coordination stays on POSIX locks; and code in the same process that takes fcntl record locks of its own on a database file — which used to never conflict with SQLite's, while quietly destroying them — now conflicts with them loudly instead. The C side — `F_OFD_SETLK` routing through a designated per-inode locking descriptor that preserves upstream's `unixInodeInfo` semantics (last-unlocker release, PENDING piggybacking, `unix-excl`), guarded to `__linux__` — ships in the transpiled sources via [libsqlite3!3](https://gitlab.com/cznic/libsqlite3/-/merge_requests/3) and its follow-up hardening, with the OFD lock constants from [libc!33](https://gitlab.com/cznic/libc/-/merge_requests/33); the review rounds, the `/proc/locks` measurements behind the design, and the Tcl lock/WAL gate that runs both modes are recorded in [GitLab issue #255](https://gitlab.com/cznic/sqlite/-/issues/255) and those merge requests. - Add the accompanying regression tests. The four OFD scenarios contributed in merge request #136 — lock survival across a rogue `os.Close`, the interleaved-readers lock lifecycle, the read-only-first designated-descriptor migration, and the failed-first-lock cleanup — run in a re-executed child process with `MODERNC_SQLITE_OFD_LOCK=1`, since the mode is process-wide and frozen at the first lock so the suite's own process cannot switch; a positive control asserts the variable really switched the mode on before each scenario runs, and the two scenarios whose invariants hold under both modes also run in the parent process's inherited mode. `TestOFDLockingSetter` exercises the Go call path end to end in a clean child — off by default, enabled before the first connection, the kernel-visible `OFDLCK` record in `/proc/locks` as the positive control, frozen after the first lock — and on every other platform the switch is asserted to report itself unavailable. - - Resolves [GitLab issue #255](https://gitlab.com/cznic/sqlite/-/issues/255). See [GitLab merge request #136](https://gitlab.com/cznic/sqlite/-/merge_requests/136), thanks @technosloth, and thanks Gani Georgiev (@ganigeorgiev) for pressing the opt-in default! + - Resolves [GitLab issue #255](https://gitlab.com/cznic/sqlite/-/issues/255). See [GitLab merge request #136](https://gitlab.com/cznic/sqlite/-/merge_requests/136), thanks Nathan Herring (@technosloth), and thanks Gani Georgiev (@ganigeorgiev) for pressing the opt-in default! - 2026-08-19 v1.57.0: - Add an opt-in `_defensive` DSN query parameter that turns on SQLite's defensive mode for the connection, disabling the SQL-level features that let ordinary statements deliberately corrupt the database file. When `_defensive=1` (or any `strconv.ParseBool` true value) is supplied, the driver calls `sqlite3_db_config` with `SQLITE_DBCONFIG_DEFENSIVE` immediately after `sqlite3_open_v2` and before every other parameter is applied, so the PRAGMAs the driver itself runs, the `_pragma` list, and every statement the caller prepares are all subject to it. On such a connection `PRAGMA writable_schema=ON`, `PRAGMA journal_mode=OFF` and `PRAGMA schema_version=N` become silent no-ops, and writes to a virtual table's shadow tables (fts5's `_data`, `_idx` and so on) and to `sqlite_dbpage` fail with "table ... may not be modified"; reading those tables, ordinary use of the virtual tables that own them, and `VACUUM` are unaffected. The flag has no PRAGMA equivalent, so `sqlite3_db_config` — and therefore a DSN parameter — is the only way to reach it short of dropping to `modernc.org/sqlite/lib`. The value is parsed before `sqlite3_open_v2`, so an invalid one fails the connection without creating the database file, and the parameter must appear at most once: a repeated `_defensive` is an error rather than letting the first value silently win. Absence of the parameter, or `_defensive=0`, leaves SQLite's default behavior unchanged; existing DSNs continue to work byte-for-byte. Two limits are worth stating plainly, since the name invites more confidence than the flag earns. Defensive mode is a hardening measure, not a sandbox for hostile database files: it is one of several steps [SQLite recommends](https://www.sqlite.org/security.html) for that purpose, and this build compiles with neither `SQLITE_TRUSTED_SCHEMA=0` nor `SQLITE_DQS=0` and exposes no authorizer. And it is a property of the connection, not of the database file — a second handle opened on the same file without the parameter is unrestricted. @@ -93,6 +102,8 @@ - This feature is exposed via the idiomatic `database/sql` escape hatch `(*sql.Conn).Raw()`, avoiding custom statement handles and keeping the standard library workflow intact. - See [GitLab merge request #113](https://gitlab.com/cznic/sqlite/-/merge_requests/113), thanks Josh Bleecher Snyder! + - 2026-04-17 v1.49.1: Documentation only: update the per-platform SQLite version table in `doc.go` to 3.53.0, the version shipped since v1.49.0. No code changes. + - 2026-04-17 v1.49.0: Upgrade to [SQLite 3.53.0](https://sqlite.org/releaselog/3_53_0.html). - Added `-DSQLITE_ENABLE_DBPAGE_VTAB` to the transpilation. See ["The SQLITE_DBPAGE Virtual Table"](https://www.sqlite.org/dbpage.html) for details. @@ -183,10 +194,43 @@ - 2026-01-18 v1.44.2: Upgrade to [SQLite 3.51.2](https://sqlite.org/releaselog/3_51_2.html). + - 2026-01-15 v1.44.1: Bump the pinned `modernc.org/libc` to v1.67.6. Its memory-safe `strlen` fixes the AddressSanitizer global-buffer-overflow in the transpiled window-function name arrays reported in [GitLab merge request #88](https://gitlab.com/cznic/sqlite/-/merge_requests/88), which was closed in favour of that upstream fix, thanks Matt Topol! + - 2026-01-13 v1.44.0: Upgrade to SQLite 3.51.1. + - 2026-01-08 v1.43.0: + - Add `IsReadOnly(schema string) (bool, error)` on the driver connection, a wrapper around `sqlite3_db_readonly`, reachable through `(*sql.Conn).Raw()`. Resolves [GitLab issue #242](https://gitlab.com/cznic/sqlite/-/issues/242). + - Honour `_time_integer_format=unix_micro` and `unix_nano` when reading integer time values back with `_inttotime=true`; previously only the seconds/milliseconds heuristic applied. Resolves [GitLab issue #240](https://gitlab.com/cznic/sqlite/-/issues/240). + - Make the mutex implementation in `lib/mutex.go` more robust. + - Re-vendor the transpiled library from `modernc.org/libsqlite3` v1.11.0; the SQLite version stays 3.50.4. + - Add openbsd/amd64 and openbsd/arm64 to the targets exercised by the builders (see [GitLab issue #237](https://gitlab.com/cznic/sqlite/-/issues/237)). + + - 2025-12-28 v1.42.2: Fix a TOCTOU race in query interruption: a cancelled context could interrupt an unrelated, later query on the same connection. Resolves [GitLab issue #241](https://gitlab.com/cznic/sqlite/-/issues/241). See [GitLab merge request #86](https://gitlab.com/cznic/sqlite/-/merge_requests/86), thanks Josh Bleecher Snyder! + + - 2025-12-27 v1.42.1: Revert to the v1.41.0 state (SQLite 3.50.4) and retract v1.42.0 in `go.mod`. + + - 2025-12-27 v1.42.0: Upgrade to SQLite 3.51.1. **Retracted** the same day as accidentally broken, see the `retract` directive in `go.mod`; v1.42.1 reverts it and v1.44.0 carries the working 3.51.1 upgrade. + + - 2025-12-08 v1.41.0: + - Add the `modernc.org/sqlite/vtab` subpackage, a Go virtual-table API (`Module`, `Table`, `Cursor`, `IndexInfo`, `vtab.RegisterModule`) bridged to the engine and validated by an in-tree dummy module. See [GitLab merge request #84](https://gitlab.com/cznic/sqlite/-/merge_requests/84), thanks Adrian Witas! + - Optimize prepared statements: reuse the prepared SQLite statement handle across executions instead of preparing it again. Updates [GitLab issue #236](https://gitlab.com/cznic/sqlite/-/issues/236). + - Fix the build on 32-bit targets. + + - 2025-11-12 v1.40.1: Close the `Rows` of a query whose context was cancelled after the statement had already produced them; such `Rows` were previously leaked, which kept a read transaction open, starved WAL checkpoints and let the WAL grow without bound. See [GitLab merge request #81](https://gitlab.com/cznic/sqlite/-/merge_requests/81), thanks Silvio Moioli! + + - 2025-10-17 v1.40.0: Add pre-update, commit and rollback hooks: `RegisterPreUpdateHook`, `RegisterCommitHook` and `RegisterRollbackHook` on the driver connection, plus the `SQLitePreUpdateData` type (`Depth`, `Count`, `Old`, `New`), reachable through `(*sql.Conn).Raw()`. Updates [GitLab issue #125](https://gitlab.com/cznic/sqlite/-/issues/125). See [GitLab merge request #80](https://gitlab.com/cznic/sqlite/-/merge_requests/80), thanks Walter Wanderley! + - 2025-10-10 v1.39.1: Upgrade to SQLite 3.50.4. + - 2025-08-11 v1.39.0: + - Add the `_time_integer_format` DSN parameter (`unix`, `unix_milli`, `unix_micro`, `unix_nano`): `time.Time` values are bound as integers in that unit instead of as text, so timestamps fit `INTEGER` columns, `STRICT` tables included. Resolves [GitLab issue #216](https://gitlab.com/cznic/sqlite/-/issues/216). See [GitLab merge request #77](https://gitlab.com/cznic/sqlite/-/merge_requests/77), thanks Guénaël Muller! + - Add the `_inttotime` DSN parameter: when enabled, `INTEGER` values read from columns declared `DATE`, `DATETIME` or `TIMESTAMP` are converted to `time.Time` (seconds, or milliseconds for magnitudes above 1e12), matching mattn/go-sqlite3, so scanning them into a `*time.Time` no longer fails. Resolves [GitLab issue #214](https://gitlab.com/cznic/sqlite/-/issues/214). See [GitLab merge request #76](https://gitlab.com/cznic/sqlite/-/merge_requests/76), thanks Harald Albrecht! + - Add a VFS unit test. See [GitLab merge request #78](https://gitlab.com/cznic/sqlite/-/merge_requests/78), thanks Harald Albrecht! + + - 2025-07-28 v1.38.2: Upgrade to SQLite 3.50.3, this time including the regenerated library that v1.38.1 lacked. + + - 2025-07-25 v1.38.1: Update dependencies. Intended as the upgrade to SQLite 3.50.3, but the regenerated library was not included, so the shipped SQLite version is still 3.50.1. Superseded by v1.38.2. + - 2025-06-09 v1.38.0: Upgrade to SQLite 3.50.1. - 2025-02-26 v1.36.0: Upgrade to SQLite 3.49.0. diff --git a/vendor/modernc.org/sqlite/CONTRIBUTORS b/vendor/modernc.org/sqlite/CONTRIBUTORS index 77c7864..e5e288e 100644 --- a/vendor/modernc.org/sqlite/CONTRIBUTORS +++ b/vendor/modernc.org/sqlite/CONTRIBUTORS @@ -34,6 +34,7 @@ Matthew Gabeler-Lee Michael Hoffmann Michael Rykov Morgan Bazalgette +Nathan Herring Prathyush PV Romain Le Disez Ross Light diff --git a/vendor/modernc.org/sqlite/README.md b/vendor/modernc.org/sqlite/README.md index 28fdc5b..8324d5f 100644 --- a/vendor/modernc.org/sqlite/README.md +++ b/vendor/modernc.org/sqlite/README.md @@ -35,6 +35,11 @@ The repository you are currently viewing might be a mirror. Please review the gu --- +Changelog +--------- + +Release notes are kept in [CHANGELOG.md](CHANGELOG.md). + Virtual Tables (vtab) --------------------- diff --git a/vendor/modernc.org/sqlite/doc.go b/vendor/modernc.org/sqlite/doc.go index 1854356..3c5580b 100644 --- a/vendor/modernc.org/sqlite/doc.go +++ b/vendor/modernc.org/sqlite/doc.go @@ -37,6 +37,11 @@ // // See the discussion at https://gitlab.com/cznic/sqlite/-/issues/177 for more details. // +// # Changelog +// +// Release notes are kept in CHANGELOG.md in the repository root, see +// https://gitlab.com/cznic/sqlite/-/blob/master/CHANGELOG.md. +// // # Thanks // // This project is sponsored by Schleibinger Geräte Teubert u. Greim GmbH by @@ -73,6 +78,51 @@ // // [The SQLite Drivers Benchmarks Game] // +// # Performance +// +// The transpiled SQLite core runs slower than the same C compiled natively. +// The gap is in CPU-bound work: the bytecode interpreter loop, b-tree page +// balancing and record building. I/O-bound work is dominated by the operating +// system either way. The ratios below are CPU time per query, measured in +// September 2026 on linux/amd64 with Go 1.27 and modernc.org/libc v1.75.7, +// against SQLite 3.53.4 compiled with the same compile-time options this +// package uses: +// +// Workload Driver vs C +// ------------------------------------------------------------------------- +// Unindexed ORDER BY ... LIMIT 100 over 584k rows of 23 columns 2.0x +// GROUP BY aggregate over the same table 1.9x +// Correlated subquery walking an index with text comparisons 1.3x +// +// Throughput across four connections scaled at least as well as the C build +// did, so the ratios hold under concurrency. +// +// Two things follow. First, this package uses the same query planner as C +// SQLite, so a query that is slow in C is slower here by the ratio above and +// no more; but a missing index costs the same ratio more, and a query that is +// merely sluggish in C can cross a deadline here. Check EXPLAIN QUERY PLAN for +// USE TEMP B-TREE and index the columns that ORDER BY, GROUP BY and WHERE use. +// Second, database/sql opens connections without limit by default. Each +// connection carries its own page cache and its own libc thread state, and a +// periodic query that takes longer than its period piles up without bound. +// Bound the pool with [sql.DB.SetMaxOpenConns] and do not issue a periodic +// query before the previous one has returned. +// +// Part of the gap is in modernc.org/libc rather than in the transpiled SQLite. +// On Linux, libc versions before v1.75.7 implemented memcpy, memmove, memset +// and memcmp as transpiled musl loops moving at most four bytes per step; +// v1.75.7 replaced them with native Go routines backed by the runtime's +// vectorized memmove, and the three workloads above went from 3.0x, 2.2x and +// 1.6x to the figures shown. The libc version this package is validated +// against is the one pinned in its go.mod, see "Fragile modernc.org/libc +// dependency" above. On the non-Linux targets memcpy and memmove are native Go +// copies already; memcmp there is still a byte loop. +// +// Because everything is Go, the usual Go tooling reaches into the SQLite core: +// a CPU profile taken with runtime/pprof attributes time to the transpiled +// SQLite functions under their C names, for example lib._balance_nonroot or +// lib.Xsqlite3_step, and to the libc routines they call. +// // # Builders // // Builder results available at: diff --git a/vendor/modernc.org/sqlite/sqlite.go b/vendor/modernc.org/sqlite/sqlite.go index a348fb6..fbf058a 100644 --- a/vendor/modernc.org/sqlite/sqlite.go +++ b/vendor/modernc.org/sqlite/sqlite.go @@ -511,8 +511,8 @@ type FunctionImpl struct { // for more details. Deterministic bool - // Scalar is called when a scalar function is invoked in SQL. The - // argument Values are not valid past the return of the function. + // Scalar is called when a scalar function is invoked in SQL. Neither ctx + // nor the argument Values are valid past the return of the function. Scalar func(ctx *FunctionContext, args []driver.Value) (driver.Value, error) // MakeAggregate is called at the beginning of each evaluation of an @@ -567,8 +567,8 @@ type FunctionImpl struct { // [application-defined window functions]: https://www.sqlite.org/windowfunctions.html#user_defined_aggregate_window_functions type AggregateFunction interface { // Step is called for each row of an aggregate function's SQL - // invocation. The argument Values are not valid past the return of the - // function. When the aggregate was registered with + // invocation. Neither ctx nor the argument Values are valid past the + // return of the function. When the aggregate was registered with // [FunctionImpl.VolatileArgs] set to true, string and []byte arguments // in rowArgs are zero-copy views into SQLite-owned memory and retaining // them produces silent data corruption — see [FunctionImpl.VolatileArgs] @@ -577,20 +577,21 @@ type AggregateFunction interface { // WindowInverse is called to remove the oldest presently aggregated // result of Step from the current window. The arguments are those - // passed to Step for the row being removed. The argument Values are not - // valid past the return of the function. The same + // passed to Step for the row being removed. Neither ctx nor the argument + // Values are valid past the return of the function. The same // [FunctionImpl.VolatileArgs] caveat applies as for Step. WindowInverse(ctx *FunctionContext, rowArgs []driver.Value) error // WindowValue is called to get the current value of an aggregate // function. This is used to return the final value of the function, - // whether it is used as a window function or not. + // whether it is used as a window function or not. The ctx is not valid + // past the return of the function. WindowValue(ctx *FunctionContext) (driver.Value, error) // Final is called after all of the aggregate function's input rows have // been stepped through. No other methods will be called on the // AggregateFunction after calling Final. WindowValue returns the value - // from the function. + // from the function. The ctx is not valid past the return of Final. Final(ctx *FunctionContext) } @@ -688,7 +689,12 @@ type ConnectionHookFn func( ) error // FunctionContext represents the context user defined functions execute in. -// Fields and/or methods of this type may get addedd in the future. +// Fields and/or methods of this type may get added in the future. +// +// The *FunctionContext passed to [FunctionImpl.Scalar] and to the +// [AggregateFunction] methods is owned by the driver and reused across +// invocations: it is valid only for the duration of the call it is passed to +// and must not be retained past its return. type FunctionContext struct { tls *libc.TLS ctx uintptr @@ -877,53 +883,64 @@ func errorResultFunction(tls *libc.TLS, ctx uintptr) func(error) { } } -// udfArgsPool reuses []driver.Value slices passed to user-defined functions. -// The driver's contract (documented on FunctionImpl.Scalar and -// AggregateFunction.Step/WindowInverse) states that the args values are not -// valid past the return of the user function, which makes the slice itself -// safe to reuse. See https://gitlab.com/cznic/sqlite/-/issues/226. -var udfArgsPool = sync.Pool{ +// udfCall is the per-invocation scratch state handed to a user-defined +// function, aggregate or virtual table callback: the argument slice and the +// FunctionContext. Both are reused across invocations through udfCallPool, so +// a callback costs no heap allocation for either. The driver's contract +// (documented on FunctionContext, FunctionImpl.Scalar and the +// AggregateFunction methods) states that neither the args values nor the +// context are valid past the return of the user callback, which is what makes +// the reuse safe. See https://gitlab.com/cznic/sqlite/-/issues/226. +type udfCall struct { + args []driver.Value + ctx FunctionContext +} + +var udfCallPool = sync.Pool{ New: func() any { - s := make([]driver.Value, 0, 8) - return &s + return &udfCall{args: make([]driver.Value, 0, 8)} }, } -// acquireUDFArgs returns a pooled *[]driver.Value with len == n. The caller -// must invoke releaseUDFArgs after the user function has returned. -func acquireUDFArgs(n int) *[]driver.Value { - sp := udfArgsPool.Get().(*[]driver.Value) - if cap(*sp) < n { - *sp = make([]driver.Value, n) +// acquireUDFCall returns a pooled udfCall whose args has len == n and whose +// ctx refers to the sqlite3_context ctx on tls. The caller must invoke +// releaseUDFCall after the user callback has returned. +func acquireUDFCall(tls *libc.TLS, ctx uintptr, n int) *udfCall { + c := udfCallPool.Get().(*udfCall) + if cap(c.args) < n { + c.args = make([]driver.Value, n) } else { - *sp = (*sp)[:n] + c.args = c.args[:n] } - return sp + c.ctx = FunctionContext{tls: tls, ctx: ctx} + return c } -// releaseUDFArgs returns the slice to the pool after clearing each entry so -// any heap references held in the previous invocation can be reclaimed. -func releaseUDFArgs(sp *[]driver.Value) { - s := *sp - for i := range s { - s[i] = nil +// releaseUDFCall returns c to the pool after clearing it so any heap +// references held by the previous invocation can be reclaimed. +func releaseUDFCall(c *udfCall) { + for i := range c.args { + c.args[i] = nil } - *sp = s[:0] - udfArgsPool.Put(sp) + c.args = c.args[:0] + c.ctx = FunctionContext{} + udfCallPool.Put(c) } -// functionArgs prepares a []driver.Value for one user-function invocation. -// The returned slice is owned by the driver and must be released via -// releaseUDFArgs once the user function returns. +// functionArgs prepares the pooled udfCall for one user-callback invocation, +// filling its args from argv. The returned call is owned by the driver and +// must be released via releaseUDFCall once the user callback returns. ctx is +// the sqlite3_context of the invocation, or 0 for virtual table callbacks, +// which have none. // // When volatile is true, SQLITE_TEXT and SQLITE_BLOB arguments are returned as // zero-copy views into SQLite-owned memory (see [FunctionImpl.VolatileArgs] // for the user-facing safety contract). When false (the default for all // existing call sites), text and blob payloads are copied into Go-owned // memory and stay valid for the lifetime of the slice. -func functionArgs(tls *libc.TLS, argc int32, argv uintptr, volatile bool) *[]driver.Value { - sp := acquireUDFArgs(int(argc)) - args := *sp +func functionArgs(tls *libc.TLS, ctx uintptr, argc int32, argv uintptr, volatile bool) *udfCall { + call := acquireUDFCall(tls, ctx, int(argc)) + args := call.args for i := int32(0); i < argc; i++ { valPtr := *(*uintptr)(unsafe.Pointer(argv + uintptr(i)*sqliteValPtrSize)) @@ -967,7 +984,7 @@ func functionArgs(tls *libc.TLS, argc int32, argv uintptr, volatile bool) *[]dri } } - return sp + return call } func functionReturnValue(tls *libc.TLS, ctx uintptr, res driver.Value) error { @@ -1166,9 +1183,9 @@ func funcTrampoline(tls *libc.TLS, ctx uintptr, argc int32, argv uintptr) { xFuncs.mu.RUnlock() setErrorResult := errorResultFunction(tls, ctx) - sp := functionArgs(tls, argc, argv, entry.volatile) - defer releaseUDFArgs(sp) - res, err := entry.fn(&FunctionContext{}, *sp) + call := functionArgs(tls, ctx, argc, argv, entry.volatile) + defer releaseUDFCall(call) + res, err := entry.fn(&call.ctx, call.args) if err != nil { setErrorResult(err) @@ -1203,9 +1220,9 @@ func stepTrampoline(tls *libc.TLS, ctx uintptr, argc int32, argv uintptr) { } setErrorResult := errorResultFunction(tls, ctx) - sp := functionArgs(tls, argc, argv, volatile) - defer releaseUDFArgs(sp) - err := impl.Step(&FunctionContext{}, *sp) + call := functionArgs(tls, ctx, argc, argv, volatile) + defer releaseUDFCall(call) + err := impl.Step(&call.ctx, call.args) if err != nil { setErrorResult(err) } @@ -1218,9 +1235,9 @@ func inverseTrampoline(tls *libc.TLS, ctx uintptr, argc int32, argv uintptr) { } setErrorResult := errorResultFunction(tls, ctx) - sp := functionArgs(tls, argc, argv, volatile) - defer releaseUDFArgs(sp) - err := impl.WindowInverse(&FunctionContext{}, *sp) + call := functionArgs(tls, ctx, argc, argv, volatile) + defer releaseUDFCall(call) + err := impl.WindowInverse(&call.ctx, call.args) if err != nil { setErrorResult(err) } @@ -1233,7 +1250,9 @@ func valueTrampoline(tls *libc.TLS, ctx uintptr) { } setErrorResult := errorResultFunction(tls, ctx) - res, err := impl.WindowValue(&FunctionContext{}) + call := acquireUDFCall(tls, ctx, 0) + defer releaseUDFCall(call) + res, err := impl.WindowValue(&call.ctx) if err != nil { setErrorResult(err) } else { @@ -1251,7 +1270,9 @@ func finalTrampoline(tls *libc.TLS, ctx uintptr) { } setErrorResult := errorResultFunction(tls, ctx) - res, err := impl.WindowValue(&FunctionContext{}) + call := acquireUDFCall(tls, ctx, 0) + defer releaseUDFCall(call) + res, err := impl.WindowValue(&call.ctx) if err != nil { setErrorResult(err) } else { @@ -1260,7 +1281,7 @@ func finalTrampoline(tls *libc.TLS, ctx uintptr) { setErrorResult(err) } } - impl.Final(&FunctionContext{}) + impl.Final(&call.ctx) xAggregateContext.mu.Lock() defer xAggregateContext.mu.Unlock() diff --git a/vendor/modernc.org/sqlite/vtab.go b/vendor/modernc.org/sqlite/vtab.go index 08118ea..488de4c 100644 --- a/vendor/modernc.org/sqlite/vtab.go +++ b/vendor/modernc.org/sqlite/vtab.go @@ -637,9 +637,9 @@ func vtabFilterTrampoline(tls *libc.TLS, pCursor uintptr, idxNum int32, idxStr u idxStrGo = libc.GoString(idxStr) } volatile := gc.table != nil && gc.table.mod != nil && gc.table.mod.volatile - sp := functionArgs(tls, argc, argv, volatile) - defer releaseUDFArgs(sp) - err := gc.impl.Filter(int(idxNum), idxStrGo, *sp) + call := functionArgs(tls, 0, argc, argv, volatile) + defer releaseUDFCall(call) + err := gc.impl.Filter(int(idxNum), idxStrGo, call.args) if err != nil { // Set zErrMsg on the associated vtab for better diagnostics. if pCursor != 0 { @@ -858,9 +858,9 @@ func vtabUpdateTrampoline(tls *libc.TLS, pVtab uintptr, argc int32, argv uintptr // Extract column values starting from argv[2] colsPtr := argv + uintptr(2)*sqliteValPtrSize volatile := gt.mod != nil && gt.mod.volatile - sp := functionArgs(tls, nCols, colsPtr, volatile) - defer releaseUDFArgs(sp) - cols := *sp + call := functionArgs(tls, 0, nCols, colsPtr, volatile) + defer releaseUDFCall(call) + cols := call.args // Determine old/new rowid oldPtr := *(*uintptr)(unsafe.Pointer(argv + uintptr(0)*sqliteValPtrSize)) diff --git a/vendor/modules.txt b/vendor/modules.txt index f208f65..9a53610 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -288,7 +288,7 @@ modernc.org/mathutil # modernc.org/memory v1.12.1 ## explicit; go 1.23.0 modernc.org/memory -# modernc.org/sqlite v1.58.0 +# modernc.org/sqlite v1.59.0 ## explicit; go 1.25.0 modernc.org/sqlite modernc.org/sqlite/lib