Skip to main content

Connection

Struct Connection 

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

A handle to a SQLRite database. Opens a file or an in-memory DB; drop it to close. Every mutating statement auto-saves (except inside an explicit BEGIN/COMMIT block — see Transactions).

§Transactions

let mut conn = Connection::open("foo.sqlrite")?;
conn.execute("BEGIN")?;
conn.execute("INSERT INTO users (name) VALUES ('alice')")?;
conn.execute("INSERT INTO users (name) VALUES ('bob')")?;
conn.execute("COMMIT")?;

§Multiple connections (Phase 10.1)

Connection is a thin handle over an Arc<Mutex<Database>>. Call Connection::connect to mint a sibling handle that shares the same backing Database — typically one per worker thread. Today every operation still serializes through the single mutex (and the pager’s exclusive flock between processes), so the headline behaviour change is that callers can hold and address the same DB from more than one thread without wrapping the whole Connection in a Mutex themselves. BEGIN CONCURRENT and snapshot-isolated reads land in subsequent Phase 10 sub-phases.

Connection is Send + Sync. The recommended pattern is one connection per thread (clone via connect()); statements still borrow &mut Connection, so a single connection isn’t suitable for true concurrent statement execution.

Implementations§

Source§

impl Connection

Source

pub fn open<P: AsRef<Path>>(path: P) -> Result<Self>

Opens (or creates) a database file for read-write access.

If the file doesn’t exist, an empty one is materialized with the current format version. Takes an exclusive advisory lock on the file and its -wal sidecar; returns Err if either is already locked by another process.

Source

pub fn open_read_only<P: AsRef<Path>>(path: P) -> Result<Self>

Opens an existing database file for read-only access. Takes a shared advisory lock, so multiple read-only connections can coexist on the same file; any open writer excludes them. Mutating statements return cannot execute: database is opened read-only.

Source

pub fn open_in_memory() -> Result<Self>

Opens a transient in-memory database. No file is touched and no locks are taken; state lives for the lifetime of the Connection and is discarded on drop.

Examples found in repository?
examples/rust/quickstart.rs (line 15)
14fn main() -> Result<()> {
15    let mut conn = Connection::open_in_memory()?;
16
17    conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER);")?;
18    conn.execute("INSERT INTO users (name, age) VALUES ('alice', 30);")?;
19    conn.execute("INSERT INTO users (name, age) VALUES ('bob', 25);")?;
20    conn.execute("INSERT INTO users (name, age) VALUES ('charlie', 40);")?;
21
22    println!("All users:");
23    let stmt = conn.prepare("SELECT id, name, age FROM users;")?;
24    let mut rows = stmt.query()?;
25    while let Some(row) = rows.next()? {
26        let id: i64 = row.get_by_name("id")?;
27        let name: String = row.get_by_name("name")?;
28        // `Option<i64>` wraps NULL cleanly — `age` is declared
29        // nullable so the typed accessor surfaces None when absent.
30        let age: Option<i64> = row.get_by_name("age")?;
31        println!(
32            "  {} — {} ({})",
33            id,
34            name,
35            age.map(|a| a.to_string())
36                .unwrap_or_else(|| "NULL".to_string())
37        );
38    }
39
40    // Transactions: BEGIN + INSERT + ROLLBACK leaves the table untouched.
41    conn.execute("BEGIN;")?;
42    conn.execute("INSERT INTO users (name, age) VALUES ('will_vanish', 99);")?;
43    println!("\nMid-transaction row count: {}", count_users(&mut conn)?);
44    conn.execute("ROLLBACK;")?;
45    println!(
46        "Post-rollback row count:   {} (unchanged)",
47        count_users(&mut conn)?
48    );
49
50    Ok(())
51}
More examples
Hide additional examples
examples/rust/concurrent_writers.rs (line 22)
21fn main() -> Result<()> {
22    let mut a = Connection::open_in_memory()?;
23    a.execute("PRAGMA journal_mode = mvcc")?;
24    a.execute(
25        "CREATE TABLE accounts (
26             id      INTEGER PRIMARY KEY,
27             holder  TEXT NOT NULL,
28             balance INTEGER NOT NULL
29         )",
30    )?;
31    a.execute("INSERT INTO accounts (id, holder, balance) VALUES (1, 'alice', 100)")?;
32    a.execute("INSERT INTO accounts (id, holder, balance) VALUES (2, 'bob',   100)")?;
33
34    // Sibling handle on the same Arc<Mutex<Database>>. In real apps
35    // you'd hand this to a worker thread; we keep it on the main
36    // thread to keep the demo readable.
37    let mut b = a.connect();
38
39    println!("=== Disjoint-row commits both succeed ===");
40    a.execute("BEGIN CONCURRENT")?;
41    b.execute("BEGIN CONCURRENT")?;
42    a.execute("UPDATE accounts SET balance = balance + 10 WHERE id = 1")?;
43    b.execute("UPDATE accounts SET balance = balance + 20 WHERE id = 2")?;
44    a.execute("COMMIT")?;
45    b.execute("COMMIT")?; // write-sets don't intersect — no conflict.
46    print_balances(&mut a)?;
47
48    println!("\n=== Same-row commits: A wins, B retries ===");
49    // Interleave BEGINs so A.begin_ts < B.begin_ts and both see the
50    // same pre-update value.
51    a.execute("BEGIN CONCURRENT")?;
52    b.execute("BEGIN CONCURRENT")?;
53    a.execute("UPDATE accounts SET balance = balance + 5 WHERE id = 1")?;
54    b.execute("UPDATE accounts SET balance = balance + 50 WHERE id = 1")?;
55    a.execute("COMMIT")?;
56    // B's commit sees a version newer than its own `begin_ts` → Busy.
57    // The transaction is already dropped on the failed COMMIT;
58    // there's no ROLLBACK to run. Start a fresh BEGIN CONCURRENT.
59    match b.execute("COMMIT") {
60        Err(e) if e.is_retryable() => {
61            eprintln!("  B lost the race: {e}");
62            b.execute("BEGIN CONCURRENT")?;
63            b.execute("UPDATE accounts SET balance = balance + 50 WHERE id = 1")?;
64            b.execute("COMMIT")?;
65        }
66        other => {
67            other?;
68        }
69    }
70    print_balances(&mut a)?;
71
72    Ok(())
73}
examples/hybrid-retrieval/hybrid_retrieval.rs (line 53)
52fn main() -> Result<()> {
53    let mut conn = Connection::open_in_memory()?;
54    conn.execute(
55        "CREATE TABLE docs (id INTEGER PRIMARY KEY, name TEXT, body TEXT, embedding VECTOR(4));",
56    )?;
57    for (name, body, vec) in CORPUS {
58        conn.execute(&format!(
59            "INSERT INTO docs (name, body, embedding) VALUES \
60             ('{name}', '{body}', [{}, {}, {}, {}]);",
61            vec[0], vec[1], vec[2], vec[3]
62        ))?;
63    }
64    conn.execute("CREATE INDEX docs_fts ON docs USING fts (body);")?;
65
66    // Same query, three rankings — see README for what each shape sees.
67    let body_query = "small embedded database";
68    let vector_query = [0.0, 0.0, 0.9, 0.2]; // semantic intent: "database, lightly web-ish"
69    let q_str = vec_lit(&vector_query);
70
71    println!("Corpus:");
72    for (name, body, vec) in CORPUS {
73        println!("  {name}: \"{body}\"  embedding={vec:?}");
74    }
75    println!("\nQuery body:   '{body_query}'");
76    println!("Query vector: {vector_query:?}\n");
77
78    println!("===  1. Pure BM25 (lexical) ===");
79    println!(
80        "WHERE  fts_match(body, '{body_query}')\n\
81         ORDER BY bm25_score(body, '{body_query}') DESC  LIMIT 3"
82    );
83    print_top(
84        &mut conn,
85        &format!(
86            "SELECT name, body FROM docs \
87             WHERE fts_match(body, '{body_query}') \
88             ORDER BY bm25_score(body, '{body_query}') DESC LIMIT 3;"
89        ),
90    )?;
91
92    println!("===  2. Pure vector (semantic) ===");
93    println!("ORDER BY vec_distance_cosine(embedding, {q_str}) ASC  LIMIT 3");
94    print_top(
95        &mut conn,
96        &format!(
97            "SELECT name, body FROM docs \
98             ORDER BY vec_distance_cosine(embedding, {q_str}) ASC LIMIT 3;"
99        ),
100    )?;
101
102    println!("===  3. Hybrid (50% BM25 + 50% inverted cosine) ===");
103    println!(
104        "WHERE  fts_match(body, '{body_query}')\n\
105         ORDER BY 0.5*bm25_score(...) + 0.5*(1.0 - vec_distance_cosine(...)) DESC  LIMIT 3"
106    );
107    print_top(
108        &mut conn,
109        &format!(
110            "SELECT name, body FROM docs \
111             WHERE fts_match(body, '{body_query}') \
112             ORDER BY 0.5 * bm25_score(body, '{body_query}') \
113                    + 0.5 * (1.0 - vec_distance_cosine(embedding, {q_str})) DESC \
114             LIMIT 3;"
115        ),
116    )?;
117    Ok(())
118}
Source

pub fn connect(&self) -> Self

Phase 10.1 — mints another Connection sharing the same backing Database. Hand the returned handle to a separate thread to address the same in-memory tables and persistent pager from there.

The new handle starts with an empty prepared-statement cache (caches are per-handle, by design). Inherits the parent’s prepare_cached capacity. Concurrent operations still serialize through the engine’s internal lock and the pager’s existing single-writer rule — a true multi-writer story arrives with BEGIN CONCURRENT in Phase 10.4.

let mut primary = Connection::open("foo.sqlrite")?;
let secondary = primary.connect();
std::thread::spawn(move || {
    let mut conn = secondary;
    conn.execute("INSERT INTO t (x) VALUES (1)").unwrap();
})
.join()
.unwrap();
Examples found in repository?
examples/rust/concurrent_writers.rs (line 37)
21fn main() -> Result<()> {
22    let mut a = Connection::open_in_memory()?;
23    a.execute("PRAGMA journal_mode = mvcc")?;
24    a.execute(
25        "CREATE TABLE accounts (
26             id      INTEGER PRIMARY KEY,
27             holder  TEXT NOT NULL,
28             balance INTEGER NOT NULL
29         )",
30    )?;
31    a.execute("INSERT INTO accounts (id, holder, balance) VALUES (1, 'alice', 100)")?;
32    a.execute("INSERT INTO accounts (id, holder, balance) VALUES (2, 'bob',   100)")?;
33
34    // Sibling handle on the same Arc<Mutex<Database>>. In real apps
35    // you'd hand this to a worker thread; we keep it on the main
36    // thread to keep the demo readable.
37    let mut b = a.connect();
38
39    println!("=== Disjoint-row commits both succeed ===");
40    a.execute("BEGIN CONCURRENT")?;
41    b.execute("BEGIN CONCURRENT")?;
42    a.execute("UPDATE accounts SET balance = balance + 10 WHERE id = 1")?;
43    b.execute("UPDATE accounts SET balance = balance + 20 WHERE id = 2")?;
44    a.execute("COMMIT")?;
45    b.execute("COMMIT")?; // write-sets don't intersect — no conflict.
46    print_balances(&mut a)?;
47
48    println!("\n=== Same-row commits: A wins, B retries ===");
49    // Interleave BEGINs so A.begin_ts < B.begin_ts and both see the
50    // same pre-update value.
51    a.execute("BEGIN CONCURRENT")?;
52    b.execute("BEGIN CONCURRENT")?;
53    a.execute("UPDATE accounts SET balance = balance + 5 WHERE id = 1")?;
54    b.execute("UPDATE accounts SET balance = balance + 50 WHERE id = 1")?;
55    a.execute("COMMIT")?;
56    // B's commit sees a version newer than its own `begin_ts` → Busy.
57    // The transaction is already dropped on the failed COMMIT;
58    // there's no ROLLBACK to run. Start a fresh BEGIN CONCURRENT.
59    match b.execute("COMMIT") {
60        Err(e) if e.is_retryable() => {
61            eprintln!("  B lost the race: {e}");
62            b.execute("BEGIN CONCURRENT")?;
63            b.execute("UPDATE accounts SET balance = balance + 50 WHERE id = 1")?;
64            b.execute("COMMIT")?;
65        }
66        other => {
67            other?;
68        }
69    }
70    print_balances(&mut a)?;
71
72    Ok(())
73}
Source

pub fn handle_count(&self) -> usize

Phase 10.1 — number of Connection handles currently sharing this database (this handle plus every live connect() descendant). Useful for diagnostics and tests; no semantic guarantee beyond that.

Source

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

Parses and executes one SQL statement. For DDL (CREATE TABLE, CREATE INDEX), DML (INSERT, UPDATE, DELETE) and transaction control (BEGIN, COMMIT, ROLLBACK, BEGIN CONCURRENT). Returns the status message the engine produced (e.g. "INSERT Statement executed.").

For SELECT, execute works but discards the row data and just returns the rendered status — use Connection::prepare and Statement::query to iterate typed rows.

Phase 11.4 — intercepts BEGIN CONCURRENT, COMMIT, and ROLLBACK before sqlparser sees them so the per-connection MVCC transaction state stays in sync. Inside an open concurrent transaction, every other statement runs against the transaction’s private cloned tables; the live database stays untouched until commit-validation succeeds.

Examples found in repository?
examples/rust/quickstart.rs (line 17)
14fn main() -> Result<()> {
15    let mut conn = Connection::open_in_memory()?;
16
17    conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER);")?;
18    conn.execute("INSERT INTO users (name, age) VALUES ('alice', 30);")?;
19    conn.execute("INSERT INTO users (name, age) VALUES ('bob', 25);")?;
20    conn.execute("INSERT INTO users (name, age) VALUES ('charlie', 40);")?;
21
22    println!("All users:");
23    let stmt = conn.prepare("SELECT id, name, age FROM users;")?;
24    let mut rows = stmt.query()?;
25    while let Some(row) = rows.next()? {
26        let id: i64 = row.get_by_name("id")?;
27        let name: String = row.get_by_name("name")?;
28        // `Option<i64>` wraps NULL cleanly — `age` is declared
29        // nullable so the typed accessor surfaces None when absent.
30        let age: Option<i64> = row.get_by_name("age")?;
31        println!(
32            "  {} — {} ({})",
33            id,
34            name,
35            age.map(|a| a.to_string())
36                .unwrap_or_else(|| "NULL".to_string())
37        );
38    }
39
40    // Transactions: BEGIN + INSERT + ROLLBACK leaves the table untouched.
41    conn.execute("BEGIN;")?;
42    conn.execute("INSERT INTO users (name, age) VALUES ('will_vanish', 99);")?;
43    println!("\nMid-transaction row count: {}", count_users(&mut conn)?);
44    conn.execute("ROLLBACK;")?;
45    println!(
46        "Post-rollback row count:   {} (unchanged)",
47        count_users(&mut conn)?
48    );
49
50    Ok(())
51}
More examples
Hide additional examples
examples/rust/concurrent_writers.rs (line 23)
21fn main() -> Result<()> {
22    let mut a = Connection::open_in_memory()?;
23    a.execute("PRAGMA journal_mode = mvcc")?;
24    a.execute(
25        "CREATE TABLE accounts (
26             id      INTEGER PRIMARY KEY,
27             holder  TEXT NOT NULL,
28             balance INTEGER NOT NULL
29         )",
30    )?;
31    a.execute("INSERT INTO accounts (id, holder, balance) VALUES (1, 'alice', 100)")?;
32    a.execute("INSERT INTO accounts (id, holder, balance) VALUES (2, 'bob',   100)")?;
33
34    // Sibling handle on the same Arc<Mutex<Database>>. In real apps
35    // you'd hand this to a worker thread; we keep it on the main
36    // thread to keep the demo readable.
37    let mut b = a.connect();
38
39    println!("=== Disjoint-row commits both succeed ===");
40    a.execute("BEGIN CONCURRENT")?;
41    b.execute("BEGIN CONCURRENT")?;
42    a.execute("UPDATE accounts SET balance = balance + 10 WHERE id = 1")?;
43    b.execute("UPDATE accounts SET balance = balance + 20 WHERE id = 2")?;
44    a.execute("COMMIT")?;
45    b.execute("COMMIT")?; // write-sets don't intersect — no conflict.
46    print_balances(&mut a)?;
47
48    println!("\n=== Same-row commits: A wins, B retries ===");
49    // Interleave BEGINs so A.begin_ts < B.begin_ts and both see the
50    // same pre-update value.
51    a.execute("BEGIN CONCURRENT")?;
52    b.execute("BEGIN CONCURRENT")?;
53    a.execute("UPDATE accounts SET balance = balance + 5 WHERE id = 1")?;
54    b.execute("UPDATE accounts SET balance = balance + 50 WHERE id = 1")?;
55    a.execute("COMMIT")?;
56    // B's commit sees a version newer than its own `begin_ts` → Busy.
57    // The transaction is already dropped on the failed COMMIT;
58    // there's no ROLLBACK to run. Start a fresh BEGIN CONCURRENT.
59    match b.execute("COMMIT") {
60        Err(e) if e.is_retryable() => {
61            eprintln!("  B lost the race: {e}");
62            b.execute("BEGIN CONCURRENT")?;
63            b.execute("UPDATE accounts SET balance = balance + 50 WHERE id = 1")?;
64            b.execute("COMMIT")?;
65        }
66        other => {
67            other?;
68        }
69    }
70    print_balances(&mut a)?;
71
72    Ok(())
73}
examples/hybrid-retrieval/hybrid_retrieval.rs (lines 54-56)
52fn main() -> Result<()> {
53    let mut conn = Connection::open_in_memory()?;
54    conn.execute(
55        "CREATE TABLE docs (id INTEGER PRIMARY KEY, name TEXT, body TEXT, embedding VECTOR(4));",
56    )?;
57    for (name, body, vec) in CORPUS {
58        conn.execute(&format!(
59            "INSERT INTO docs (name, body, embedding) VALUES \
60             ('{name}', '{body}', [{}, {}, {}, {}]);",
61            vec[0], vec[1], vec[2], vec[3]
62        ))?;
63    }
64    conn.execute("CREATE INDEX docs_fts ON docs USING fts (body);")?;
65
66    // Same query, three rankings — see README for what each shape sees.
67    let body_query = "small embedded database";
68    let vector_query = [0.0, 0.0, 0.9, 0.2]; // semantic intent: "database, lightly web-ish"
69    let q_str = vec_lit(&vector_query);
70
71    println!("Corpus:");
72    for (name, body, vec) in CORPUS {
73        println!("  {name}: \"{body}\"  embedding={vec:?}");
74    }
75    println!("\nQuery body:   '{body_query}'");
76    println!("Query vector: {vector_query:?}\n");
77
78    println!("===  1. Pure BM25 (lexical) ===");
79    println!(
80        "WHERE  fts_match(body, '{body_query}')\n\
81         ORDER BY bm25_score(body, '{body_query}') DESC  LIMIT 3"
82    );
83    print_top(
84        &mut conn,
85        &format!(
86            "SELECT name, body FROM docs \
87             WHERE fts_match(body, '{body_query}') \
88             ORDER BY bm25_score(body, '{body_query}') DESC LIMIT 3;"
89        ),
90    )?;
91
92    println!("===  2. Pure vector (semantic) ===");
93    println!("ORDER BY vec_distance_cosine(embedding, {q_str}) ASC  LIMIT 3");
94    print_top(
95        &mut conn,
96        &format!(
97            "SELECT name, body FROM docs \
98             ORDER BY vec_distance_cosine(embedding, {q_str}) ASC LIMIT 3;"
99        ),
100    )?;
101
102    println!("===  3. Hybrid (50% BM25 + 50% inverted cosine) ===");
103    println!(
104        "WHERE  fts_match(body, '{body_query}')\n\
105         ORDER BY 0.5*bm25_score(...) + 0.5*(1.0 - vec_distance_cosine(...)) DESC  LIMIT 3"
106    );
107    print_top(
108        &mut conn,
109        &format!(
110            "SELECT name, body FROM docs \
111             WHERE fts_match(body, '{body_query}') \
112             ORDER BY 0.5 * bm25_score(body, '{body_query}') \
113                    + 0.5 * (1.0 - vec_distance_cosine(embedding, {q_str})) DESC \
114             LIMIT 3;"
115        ),
116    )?;
117    Ok(())
118}
Source

pub fn execute_with_render(&mut self, sql: &str) -> Result<CommandOutput>

Phase 11.11a — same as Connection::execute, but returns the full [CommandOutput] (status + optional pre-rendered prettytable for SELECT). The REPL needs this to print the table the engine produced and the status line in one pass, while still routing BEGIN CONCURRENT / COMMIT / ROLLBACK through the per-connection MVCC state.

BEGIN / COMMIT / ROLLBACK carry no rendered output — they return CommandOutput { status, rendered: None }.

Source

pub fn concurrent_tx_is_open(&self) -> bool

Phase 11.5 — cheap probe used by Connection::execute (and Statement::query) to decide whether to route through the concurrent-tx dispatch. Acquires the concurrent_tx mutex briefly; never blocks for a meaningful amount of time because the only other lockers are this connection’s own writers.

Public so the REPL can render per-handle tx state in .conns output (Phase 11.11a).

Source

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

Prepares a statement for repeated execution or row iteration. SQLR-23: the SQL is parsed once at prepare time (sqlparser walk plus placeholder rewriting), and the resulting AST is cached on the Statement for re-execution without further parsing.

Use Statement::query / Statement::run for unbound execution, or Statement::query_with_params / Statement::execute_with_params to substitute ? placeholders.

Examples found in repository?
examples/hybrid-retrieval/hybrid_retrieval.rs (line 126)
125fn print_top(conn: &mut Connection, sql: &str) -> Result<()> {
126    let stmt = conn.prepare(sql)?;
127    let mut rows = stmt.query()?;
128    let mut rank = 1;
129    while let Some(row) = rows.next()? {
130        let name: String = row.get_by_name("name")?;
131        let body: String = row.get_by_name("body")?;
132        println!("  {rank}. {name}  \"{body}\"");
133        rank += 1;
134    }
135    println!();
136    Ok(())
137}
More examples
Hide additional examples
examples/rust/concurrent_writers.rs (line 76)
75fn print_balances(conn: &mut Connection) -> Result<()> {
76    let stmt = conn.prepare("SELECT id, holder, balance FROM accounts ORDER BY id")?;
77    let mut rows = stmt.query()?;
78    while let Some(row) = rows.next()? {
79        let id: i64 = row.get_by_name("id")?;
80        let holder: String = row.get_by_name("holder")?;
81        let balance: i64 = row.get_by_name("balance")?;
82        println!("  account {id} ({holder}): {balance}");
83    }
84    Ok(())
85}
examples/rust/quickstart.rs (line 23)
14fn main() -> Result<()> {
15    let mut conn = Connection::open_in_memory()?;
16
17    conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER);")?;
18    conn.execute("INSERT INTO users (name, age) VALUES ('alice', 30);")?;
19    conn.execute("INSERT INTO users (name, age) VALUES ('bob', 25);")?;
20    conn.execute("INSERT INTO users (name, age) VALUES ('charlie', 40);")?;
21
22    println!("All users:");
23    let stmt = conn.prepare("SELECT id, name, age FROM users;")?;
24    let mut rows = stmt.query()?;
25    while let Some(row) = rows.next()? {
26        let id: i64 = row.get_by_name("id")?;
27        let name: String = row.get_by_name("name")?;
28        // `Option<i64>` wraps NULL cleanly — `age` is declared
29        // nullable so the typed accessor surfaces None when absent.
30        let age: Option<i64> = row.get_by_name("age")?;
31        println!(
32            "  {} — {} ({})",
33            id,
34            name,
35            age.map(|a| a.to_string())
36                .unwrap_or_else(|| "NULL".to_string())
37        );
38    }
39
40    // Transactions: BEGIN + INSERT + ROLLBACK leaves the table untouched.
41    conn.execute("BEGIN;")?;
42    conn.execute("INSERT INTO users (name, age) VALUES ('will_vanish', 99);")?;
43    println!("\nMid-transaction row count: {}", count_users(&mut conn)?);
44    conn.execute("ROLLBACK;")?;
45    println!(
46        "Post-rollback row count:   {} (unchanged)",
47        count_users(&mut conn)?
48    );
49
50    Ok(())
51}
52
53fn count_users(conn: &mut Connection) -> Result<usize> {
54    let stmt = conn.prepare("SELECT id FROM users;")?;
55    let rows = stmt.query()?.collect_all()?;
56    Ok(rows.len())
57}
Source

pub fn prepare_cached<'c>(&'c mut self, sql: &str) -> Result<Statement<'c>>

Same as Connection::prepare, but consults a small per-connection LRU first. SQLR-23 — for hot statements (the body of an INSERT loop, a frequently-rerun lookup) the sqlparser walk is amortized to once across the connection’s lifetime, not once per prepare().

Default cache capacity is 16; tune with Connection::set_prepared_cache_capacity.

Source

pub fn set_prepared_cache_capacity(&mut self, cap: usize)

SQLR-23 — sets the maximum number of cached prepared plans (matches prepare_cached’s default 16). Reducing below the current size evicts the oldest entries; setting to 0 disables caching but prepare_cached still works (it just always re-parses).

Source

pub fn prepared_cache_len(&self) -> usize

SQLR-23 — current number of plans held by the prepared-statement cache. Useful for tests / introspection; not load-bearing for the public API.

Source

pub fn in_transaction(&self) -> bool

Returns true while a BEGIN … COMMIT/ROLLBACK block is open against this connection.

Source

pub fn auto_vacuum_threshold(&self) -> Option<f32>

Returns the current auto-VACUUM threshold (SQLR-10). After a page-releasing DDL (DROP TABLE / DROP INDEX / ALTER TABLE DROP COLUMN) commits, the engine compacts the file in place if the freelist exceeds this fraction of page_count. New connections default to Some(0.25) (SQLite parity); None means the trigger is disabled. See Connection::set_auto_vacuum_threshold.

Source

pub fn set_auto_vacuum_threshold( &mut self, threshold: Option<f32>, ) -> Result<()>

Sets the auto-VACUUM threshold (SQLR-10). Some(t) with t in 0.0..=1.0 arms the trigger; None disables it. Values outside 0.0..=1.0 (or NaN / infinite) return a typed error rather than silently saturating. The setting is per-database runtime state — closing the last connection to a database drops it; new connections start at the default Some(0.25).

Calling this on an in-memory or read-only database is allowed (it just won’t fire — there’s nothing to compact / no writes will reach the trigger).

Source

pub fn is_read_only(&self) -> bool

Returns true if the connection was opened read-only. Mutating statements on a read-only connection return a typed error.

Source

pub fn journal_mode(&self) -> JournalMode

Phase 11.3 — current journal mode. Wal (default) keeps every pre-Phase-11 caller’s behaviour. Mvcc is opt-in via PRAGMA journal_mode = mvcc;. Per-database — every Connection::connect sibling sees the same value.

Today this is observable but doesn’t change query behaviour; 11.4 wires Mvcc mode into the read/write paths.

Source

pub fn vacuum_mvcc(&self) -> usize

Phase 11.6 — explicit full-store MVCC garbage collection pass. Walks every row in the MvStore chain and drops versions whose end timestamp is below the current watermark (the smallest begin_ts across all in-flight transactions on this database, or u64::MAX when nothing is in flight).

Returns the number of versions reclaimed. Cheap when the store is small; a future optimisation will give it background-thread semantics behind a configurable cadence.

Per-commit GC already sweeps the rows each transaction touched, so most callers don’t need this — it’s the “vacuum the whole store” escape hatch for memory-pressure workloads or test suites that want a deterministic baseline. Safe to call even if journal_mode is Wal (the store is just empty); useful for tests that want to assert “no versions left.”

Trait Implementations§

Source§

impl ConnectionAskExt for Connection

Available on crate feature ask only.
Source§

fn ask( &self, question: &str, config: &AskConfig, ) -> Result<AskResponse, AskError>

Generate SQL from a natural-language question. Read more
Source§

impl Debug for Connection

Source§

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

Formats the value using the given formatter. 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.