Prerequisites
An extension that uses any preview capability installs only whenvsql_allow_preview_extensions is ON:
SET GLOBAL is rejected for this variable.
You also need a working Rust extension setup — the
Creating Extensions in Rust walkthrough covers the
toolchain, cargo-vsql, and your first extension! block.
What the Rust SDK Wraps
The remaining preview capabilities —
sql_query, statement_event, and the
column storage ABI — are C++-only today. Use the
C++ SDK if you need one of those.
Registration Pattern
Declare each capability as astatic, then list it by reference in the
requires: section of extension! — the Rust equivalent of the C++ SDK’s
.with():
static is required — the server holds pointers into the capability for
the extension’s whole lifetime.
Status Variables
Thestatus_var capability exposes extension-owned counters through
SHOW GLOBAL STATUS. Your extension owns the storage as 'static atomics
and writes to them; the server reads through the pointers each time the
status variable is queried.
Declare each variable as a StatusVarSpec — Int backed by an
AtomicI64, or Double backed by the SDK’s AtomicF64 (Rust’s standard
library has no atomic f64, so the SDK provides one with new, load, and
store):
INSTALL EXTENSION, the variables appear with the extension name as a
prefix:
System Variables
Thesys_var capability registers MySQL system variables owned by your
extension. Three types are supported: Bool, Int (with min/max
bounds), and Str. Every spec carries a name, a comment shown in
SHOW VARIABLES metadata, a default, and an optional on_change callback.
Names and string defaults are &'static CStr values — write them as C-string
literals (c"enabled"):
funcs: section must be present before requires:, even when empty.
After install, the variables are addressable with the extension name as a
prefix:
Reacting to Changes
on_change is a raw C callback, invoked by the server after a variable is
set. It runs on the server’s thread: keep it quick, and don’t panic — a
panic here crosses the FFI boundary. The callback receives a
*const vef_sys_var_change_t from the raw ABI layer:
on_change: Some(on_enabled_change).
Reading and Writing from Extension Code
SysVarCapability also exposes get() and set() for programmatic access
through the server (so range validation and persistence are handled for
you). set() takes a scope argument that selects persistence: null
changes only the running value, so it reverts on restart; "PERSIST" changes
the running value and writes it to the persisted config; "PERSIST_ONLY"
writes to the persisted config without touching the running value, so it
applies on the next restart. Both are unsafe FFI methods taking
NUL-terminated C strings, and
both use the inverted C convention: Some(false) means success, Some(true)
means the server reported an error, and None means the capability is
unavailable. On a successful get, the server writes a malloc’d string
you must release with the C free(). The
vsql_sys_var example
shows the full pattern, including the free extern and the safety
comments.
Thread Worker
Thethread_worker capability runs a function you provide on a
server-managed background thread. The server registers a control system
variable at load time; while it is ON, your work function is called on a
periodic timer, on file-descriptor readiness, or on enable/disable
transitions.
Your work function is plain safe Rust:
ThreadWorkerCapability::new takes the work function, a thread-name suffix,
the initial sleep interval, and an optional control-variable name override.
When the override is None, the control variable is named
{suffix}_enabled and registered under the extension’s prefix:
Wakeups
WakeupReason tells you why the server called: Enable, Periodic,
PollFd, or Disable. Your return value adjusts the next wakeup:
NextWakeup::unchanged()— keep the current sleep interval and poll fd.NextWakeup::after(duration)— wake again afterduration.- Set the
poll_fdfield to a file descriptor greater than zero to also wake when it becomes readable, or to-1to clear a previously set one.
Duration collapses to “no change” — the underlying C ABI
reserves 0 for that, so an instant wakeup can’t be expressed.
If the work function panics, the SDK catches the panic at the FFI boundary
and treats the call as returning NextWakeup::unchanged() — the worker
keeps running.
The ThreadHandle parameter is reserved for opening SQL sessions from the
worker once the sql_query capability is ported to Rust; it has no methods
yet.
Keyring Access
Thekeyring capability reads and writes secrets stored in the MySQL
keyring component — API keys, encryption keys, anything that shouldn’t live
in a table. A keyring component (for example component_keyring_file) must
be installed on the server; without one, every read and write fails with
KeyringError::NoComponent.
read(data_id, auth_id, buf) fills the buffer you pass and returns
Ok(Some(n)) with the secret’s length, or Ok(None) when no secret exists
under data_id — a normal outcome, not an error. write(data_id, auth_id, data) returns Ok(()) on success. auth_id is the owning user; pass
None for internal keys not associated with a specific user.
Both return Err(KeyringError) on failure: CapabilityUnavailable (the
capability was never wired up), NoComponent (no keyring component on the
server), or Other.
The keyring has no size probe: a secret larger than the buffer you pass to
read comes back as Ok(None), indistinguishable from a missing key. Size
your buffer for the largest secret you expect to store.
Next Steps
Preview Capabilities (C++)
The full capability index, the preview tier, and the C++-only
capabilities: sql_query, statement_event, and column storage.
Rust API Reference
InValue, VdfReturn, extension!, func!, and custom_type! — all fields.

