Skip to main content

Database

Struct Database 

Source
pub struct Database { /* private fields */ }
Expand description

Embedded SPG database handle. Owns an Engine + provides ergonomic wrappers around execute and query. Drops the engine on Drop — no WAL flush / fsync, because v6.10.3 is in-memory only.

Implementations§

Source§

impl Database

Source

pub fn open_in_memory() -> Self

Open a fresh in-memory database. No WAL, no catalog snapshot on disk — perfect for tests + short-lived CLI tools.

Source

pub fn open_path(db_path: impl AsRef<Path>) -> Result<Self, EngineError>

v7.1 — Open or create a persistent database backed by the file at db_path. The WAL lives at db_path + “.wal” (e.g. ./data/spg.db./data/spg.db.wal). Boot path:

  1. If db_path exists, restore the catalog snapshot.
  2. If the WAL exists, replay every record into the restored engine — the same recovery story spg-server uses.
  3. Open the WAL in append+sync mode so subsequent execute() writes durably commit (one fsync per mutation).

Drop writes a final catalog snapshot + truncates the WAL — operators that need a sync barrier at a specific point use checkpoint() explicitly.

Source

pub fn freeze_oldest_to_cold( &mut self, table_name: &str, index_name: &str, max_rows: usize, ) -> Result<FreezeReport, EngineError>

v7.1.4 — freeze the oldest max_rows of table_name’s hot tier into a brand-new cold-tier segment + persist it to disk. Same semantics as spg-server’s freezer thread; embedded just runs the freeze synchronously on the caller’s thread. Persistence + manifest update happen as part of the next checkpoint() (or on Drop).

Source

pub fn set_checkpoint_threshold_bytes(&mut self, bytes: u64)

v7.1 — override the auto-checkpoint WAL-size ceiling for this Database instance. Default is SPG_EMBEDDED_CHECKPOINT_BYTES env (4 MiB if unset); the setter wins. No-op when the database is in-memory.

Source

pub fn checkpoint(&mut self) -> Result<(), EngineError>

v7.1 — flush a fresh catalog snapshot to db_path and truncate the WAL. Idempotent; cheap when nothing has happened since the last checkpoint. No-op when the database is in-memory (no db_path configured).

Called automatically when:

  • the WAL grows past SPG_EMBEDDED_CHECKPOINT_BYTES (default 4 MiB) at the end of an execute(), and
  • Drop runs (best-effort; checkpoint failure on drop is logged to stderr).
Source

pub fn restore(snapshot: &[u8]) -> Result<Self, EngineError>

Restore a database from a previously-captured catalog snapshot. Pairs with Database::snapshot() for round-tripping in-memory state without going through the spg-server WAL.

Source

pub fn snapshot(&self) -> Vec<u8>

Take a catalog snapshot suitable for Database::restore. The bytes are SPG’s canonical catalog envelope (FILE_MAGIC

  • version + payload); round-trips through every released SPG version per the STABILITY contract.
Source

pub fn execute(&mut self, sql: &str) -> Result<QueryResult, EngineError>

Execute a SQL statement and return the engine’s QueryResult verbatim. Pass-through for callers that want to keep PG-flavoured column/row metadata.

v7.1 — when the database was opened via open_path, successful mutations are appended to the WAL + fsynced before the call returns. A subsequent process crash will recover state up to the last successful return from execute(). Read-only statements (SELECT / SHOW / EXPLAIN / BEGIN-COMMIT-ROLLBACK / CHECKPOINT / COMPACT etc.) skip the WAL entirely.

Source

pub fn query_typed<T: FromSpgRow>( &mut self, sql: &str, ) -> Result<Vec<T>, EngineError>

v7.3.0 — typed-row variant of Database::query. Each row decodes into a T: FromSpgRow so callers don’t pattern-match on Value themselves. Use spg_row! to generate the impl, or write it by hand.

Source

pub fn query(&mut self, sql: &str) -> Result<Vec<Vec<Value>>, EngineError>

Run a SELECT and return rows as a Vec<Vec<Value>> — strips the column-schema metadata for read-side ergonomics. Errors on non-Rows results (DML / DDL statements should go through execute instead).

Source

pub fn query_with_columns( &mut self, sql: &str, ) -> Result<(Vec<ColumnSchema>, Vec<Vec<Value>>), EngineError>

v7.16.0 — column-aware variant of Self::query. Returns the column schema vec alongside the rows so adapters (the spg-sqlx Row impl most notably) can drive name + type-based column lookups. Errors on non-Rows results identically to query.

Source

pub fn query_prepared_with_columns( &mut self, stmt: &Statement, params: &[Value], ) -> Result<(Vec<ColumnSchema>, Vec<Vec<Value>>), EngineError>

v7.16.0 — column-aware variant of Self::query_prepared. Same shape as query_with_columns but driven from a prepared statement + bound params.

Source

pub const fn engine(&self) -> &Engine

Borrow the underlying engine. Escape hatch for callers that need access to spg-engine APIs not yet surfaced here (transactions, EXPLAIN ANALYZE, etc.).

Source

pub const fn engine_mut(&mut self) -> &mut Engine

Mutable borrow of the underlying engine. Same intent as engine() but for write-side APIs (e.g. inserting directly through Catalog::insert for high-throughput bulk loads that bypass SQL parsing).

Source

pub fn prepare(&mut self, sql: &str) -> Result<Statement, EngineError>

v7.16.0 — parse + plan a SQL string ONCE so subsequent execute_prepared / query_prepared calls can re-bind parameters without re-parsing. The returned Statement is a thin handle around the AST + cached source SQL; it’s Clone so the same plan can drive many bind calls concurrently (each call clones the AST and runs placeholder substitution on the clone — the cached plan stays intact).

Plan caching follows the engine’s existing version-aware rule: a prepared Statement whose statistics version has rolled (ANALYZE ran between prepare and execute) will silently re-prepare under the hood. Callers don’t need to detect this.

Placeholders in the SQL use PG’s $1, $2, … convention. bind-time Values are passed as a slice; arity mismatches surface as EvalError::PlaceholderOutOfRange at execute_prepared time, not here.

§Errors

Surfaces EngineError (parse error / plan rewrite failure) from the underlying Engine::prepare.

Source

pub fn execute_prepared( &mut self, stmt: &Statement, params: &[Value], ) -> Result<QueryResult, EngineError>

v7.16.0 — execute a prepared statement with bound parameters. Mirrors Engine::execute_prepared: clones the AST, substitutes $1..$Nparams[0..N-1], runs.

Persistence (WAL fsync + auto-checkpoint) follows the same rules as execute(sql): mutating statements get a WAL record AFTER the in-memory exec succeeds. The WAL record carries the substituted, bind-final SQL, so replay reconstructs the same row state without needing the original prepared Statement to still be alive.

§Errors

Propagates engine errors. Param arity mismatch surfaces as EvalError::PlaceholderOutOfRange.

Source

pub fn query_prepared( &mut self, stmt: &Statement, params: &[Value], ) -> Result<Vec<Vec<Value>>, EngineError>

v7.16.0 — run a prepared SELECT with bound params and return rows as Vec<Vec<Value>>, matching query() shape. SELECTs are read-only so this never writes the WAL.

§Errors

Returns Unsupported if the prepared statement isn’t a SELECT (use execute_prepared for DML/DDL).

Source

pub fn with_transaction<R, F>(&mut self, body: F) -> Result<R, EngineError>
where F: FnOnce(&mut Self) -> Result<R, EngineError>,

v7.2.0 — run body inside an implicit BEGIN / COMMIT pair. The body receives &mut Database so it can execute() / query() like any other code path; the only difference is that every write in the body lands inside one transaction, and a returned Err from the body triggers ROLLBACK before the error propagates.

Nested calls are not supported — SPG’s transaction model is single-writer with explicit BEGIN / COMMIT / ROLLBACK, and a nested with_transaction would hit EngineError::Unsupported("nested transaction") at the inner BEGIN.

Source§

impl Database

Source

pub fn cold_segment_count(&self) -> usize

v7.7.4 — observe the catalog’s cold-segment count. Useful for tests + dashboards that want to verify auto-compaction is firing.

Source

pub fn metrics(&self) -> EmbeddedMetrics

v7.7.5 — observability snapshot. Returns a point-in-time view of the engine + persistence counters. Cheap (no locks beyond the existing &self borrow), so safe to call from a hot metrics-scrape path.

Fields mirror the operational dashboard spg-server exposes, minus the network counters that don’t apply to embedded.

Source

pub fn spawn_background_freezer( db: Arc<Mutex<Database>>, opts: FreezerOptions, ) -> FreezerHandle

v7.2.1 — spawn a background thread that periodically runs freeze_oldest_to_cold when the catalog-wide hot tier exceeds opts.hot_tier_bytes. The Arc<Mutex<_>> pattern matches the v7.2 sharing story: callers wrap their Database in Arc::new(Mutex::new(db)) once, then clone the Arc for the worker + for foreground access. Return value is a handle whose Drop joins the worker.

Picks the freeze target the same way spg-server’s freezer does: largest-hot_bytes user table with at least one BTree integer-PK index. Tables without a freezable index are skipped silently.

Trait Implementations§

Source§

impl Debug for Database

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Database

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl Drop for Database

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.