Skip to content

feat: add support for registering scalar functions - #66

Merged
velocitysystems merged 5 commits into
masterfrom
function-registration
Aug 21, 2026
Merged

feat: add support for registering scalar functions#66
velocitysystems merged 5 commits into
masterfrom
function-registration

Conversation

@onebytegone

Copy link
Copy Markdown
Contributor

No description provided.

@onebytegone
onebytegone requested review from a team and pmorris-dev August 21, 2026 12:01

@velocitysystems velocitysystems left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work @onebytegone. Some curated review comments for your consideration.

Comment thread CHANGELOG.md Outdated
Comment thread crates/sqlx-sqlite-conn-mgr/tests/function_tests.rs
Comment thread crates/sqlx-sqlite-conn-mgr/src/functions.rs Outdated
Comment thread crates/sqlx-sqlite-conn-mgr/src/functions.rs Outdated
Comment thread crates/sqlx-sqlite-conn-mgr/src/functions.rs Outdated
Comment thread crates/sqlx-sqlite-conn-mgr/src/functions.rs Outdated
Comment thread crates/sqlx-sqlite-conn-mgr/tests/function_tests.rs
Comment thread src/lib.rs
`register_function` records a Rust scalar function in a process-global set. Both
connection pools install that whole set on each connection they open, through
`after_connect`, so a function is present before any caller can use the connection and
remains present as the pools drop idle connections and open new ones.

Registration validates the name, the arity, and the name-and-arity pair against the set,
so a bad registration fails at the call site. SQLite owns one strong reference to each
registration per connection and releases it through the `xDestroy` callback when the
connection closes.

A handler error becomes the statement's SQLite error, carrying the handler's message. A
handler panic becomes an error naming the function, because an unwind across the FFI
boundary would abort the process.
Asserts what a consumer depends on: a registered function resolves on a read connection
and on the write connection, on every connection a growing read pool opens, and on the
connection that replaces one the idle reaper dropped.

Also covers the two failure paths. A handler error carries its message to the caller, and
a handler panic produces an error naming the function while leaving the pool usable.
`Builder::register_function` and `SetupRegistrar::register_function` register a function
for every database the plugin serves. The registrar variant exists for a handler that
closes over the `app` instance; the builder variant covers everything else.

Registration happens at the call rather than at `build()`, so a validation error names the
offending function where a developer wrote it.

The toolkit and the plugin both re-export the function types, so a consumer does not
depend on the connection manager directly.
Both READMEs carry the same contract: a function belongs to a connection rather than to a
database file, registration precedes the first open, and the handler runs on the
connection's own thread.

Also states what the mechanism cannot promise. A handler panic becomes an error only where
the application unwinds on panic, and aggregate functions, window functions, collations,
virtual tables, and functions defined in JavaScript are out of scope.
Registers a function on the builder, then reads a column through it with the `fetch_all`
command, which is the path a consumer's frontend takes. The layers underneath have their
own tests; this one asserts that the builder entry point and the pools meet.
@velocitysystems
velocitysystems merged commit 92eb191 into master Aug 21, 2026
2 checks passed
@velocitysystems
velocitysystems deleted the function-registration branch August 21, 2026 21:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants