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
impl Connection
Sourcepub fn open<P: AsRef<Path>>(path: P) -> Result<Self>
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.
Sourcepub fn open_read_only<P: AsRef<Path>>(path: P) -> Result<Self>
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.
Sourcepub fn open_in_memory() -> Result<Self>
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?
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
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}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}Sourcepub fn connect(&self) -> Self
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?
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}Sourcepub fn handle_count(&self) -> usize
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.
Sourcepub fn execute(&mut self, sql: &str) -> Result<String>
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?
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
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}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}Sourcepub fn execute_with_render(&mut self, sql: &str) -> Result<CommandOutput>
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 }.
Sourcepub fn concurrent_tx_is_open(&self) -> bool
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).
Sourcepub fn prepare<'c>(&'c mut self, sql: &str) -> Result<Statement<'c>>
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?
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
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}Sourcepub fn prepare_cached<'c>(&'c mut self, sql: &str) -> Result<Statement<'c>>
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.
Sourcepub fn set_prepared_cache_capacity(&mut self, cap: usize)
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).
Sourcepub fn prepared_cache_len(&self) -> usize
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.
Sourcepub fn in_transaction(&self) -> bool
pub fn in_transaction(&self) -> bool
Returns true while a BEGIN … COMMIT/ROLLBACK block is open
against this connection.
Sourcepub fn auto_vacuum_threshold(&self) -> Option<f32>
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.
Sourcepub fn set_auto_vacuum_threshold(
&mut self,
threshold: Option<f32>,
) -> Result<()>
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).
Sourcepub fn is_read_only(&self) -> bool
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.
Sourcepub fn journal_mode(&self) -> JournalMode
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.
Sourcepub fn vacuum_mvcc(&self) -> usize
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.
impl ConnectionAskExt for Connection
ask only.