Files
sausage/sdk/src/sqlite.rs
T
2026-10-28 00:33:33 +00:00

44 lines
2.0 KiB
Rust

//! Shared SQLite open policy, expanded against the plugin's own rusqlite version.
/// Open SQLite under an already-held Sausage host lock. The caller must depend
/// on `rusqlite` (bundled) and hold the SAME host lock for EVERY connection's
/// entire lifetime, including reads and old/new plugin versions. This macro does
/// not acquire the lock. Do not use it for the host journal or databases accessed
/// outside Sausage. Native builds retain OS locks; WASI selects `unix-none`, so
/// crash-leftover dotfile lock directories cannot block recovery.
///
/// Temporary tables/sorts stay in memory before any schema access. Writable opens
/// use DELETE journals; SQLite rolls back hot journals itself. Never delete a
/// leftover journal. Read-only opens cannot recover a hot journal: recover with
/// a writable open first.
///
/// The flags form preserves the caller's open flags. A macro avoids coupling the
/// SDK to a particular rusqlite/libsqlite3-sys version (the host and plugins use
/// different versions, which cannot coexist as dependencies due to `links`).
///
/// ```ignore
/// let _guard = sausage_plugin::lock("/state/example/db.lock").await?;
/// let c = sausage_plugin::sqlite_open!("/state/example/db.sqlite")?;
/// // Query here; c must drop before _guard.
/// ```
#[macro_export]
macro_rules! sqlite_open {
($path:expr) => {
$crate::sqlite_open!($path, ::rusqlite::OpenFlags::default())
};
($path:expr, $flags:expr) => {{
(|| -> ::rusqlite::Result<::rusqlite::Connection> {
let flags = $flags;
#[cfg(target_os = "wasi")]
let c = ::rusqlite::Connection::open_with_flags_and_vfs($path, flags, "unix-none")?;
#[cfg(not(target_os = "wasi"))]
let c = ::rusqlite::Connection::open_with_flags($path, flags)?;
c.pragma_update(None, "temp_store", "MEMORY")?;
if !flags.contains(::rusqlite::OpenFlags::SQLITE_OPEN_READ_ONLY) {
c.pragma_update(None, "journal_mode", "DELETE")?;
}
Ok(c)
})()
}};
}