use sqlrite::{Connection, Result};
fn main() -> Result<()> {
let mut a = Connection::open_in_memory()?;
a.execute("PRAGMA journal_mode = mvcc")?;
a.execute(
"CREATE TABLE accounts (
id INTEGER PRIMARY KEY,
holder TEXT NOT NULL,
balance INTEGER NOT NULL
)",
)?;
a.execute("INSERT INTO accounts (id, holder, balance) VALUES (1, 'alice', 100)")?;
a.execute("INSERT INTO accounts (id, holder, balance) VALUES (2, 'bob', 100)")?;
let mut b = a.connect();
println!("=== Disjoint-row commits both succeed ===");
a.execute("BEGIN CONCURRENT")?;
b.execute("BEGIN CONCURRENT")?;
a.execute("UPDATE accounts SET balance = balance + 10 WHERE id = 1")?;
b.execute("UPDATE accounts SET balance = balance + 20 WHERE id = 2")?;
a.execute("COMMIT")?;
b.execute("COMMIT")?; print_balances(&mut a)?;
println!("\n=== Same-row commits: A wins, B retries ===");
a.execute("BEGIN CONCURRENT")?;
b.execute("BEGIN CONCURRENT")?;
a.execute("UPDATE accounts SET balance = balance + 5 WHERE id = 1")?;
b.execute("UPDATE accounts SET balance = balance + 50 WHERE id = 1")?;
a.execute("COMMIT")?;
match b.execute("COMMIT") {
Err(e) if e.is_retryable() => {
eprintln!(" B lost the race: {e}");
b.execute("BEGIN CONCURRENT")?;
b.execute("UPDATE accounts SET balance = balance + 50 WHERE id = 1")?;
b.execute("COMMIT")?;
}
other => {
other?;
}
}
print_balances(&mut a)?;
Ok(())
}
fn print_balances(conn: &mut Connection) -> Result<()> {
let stmt = conn.prepare("SELECT id, holder, balance FROM accounts ORDER BY id")?;
let mut rows = stmt.query()?;
while let Some(row) = rows.next()? {
let id: i64 = row.get_by_name("id")?;
let holder: String = row.get_by_name("holder")?;
let balance: i64 = row.get_by_name("balance")?;
println!(" account {id} ({holder}): {balance}");
}
Ok(())
}