use stoolap::{Database, IsolationLevel};
#[test]
fn test_snapshot_isolation_cold_update() {
let dir = tempfile::tempdir().unwrap();
let dsn = format!("file://{}", dir.path().to_str().unwrap());
let db = Database::open(&dsn).unwrap();
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, val TEXT)", ())
.unwrap();
db.execute("INSERT INTO t VALUES (1, 'orig')", ()).unwrap();
db.execute("PRAGMA CHECKPOINT", ()).unwrap();
let mut tx = db
.begin_with_isolation(IsolationLevel::SnapshotIsolation)
.unwrap();
let before: String = tx.query_one("SELECT val FROM t WHERE id = 1", ()).unwrap();
assert_eq!(before, "orig");
db.execute("UPDATE t SET val = 'new1' WHERE id = 1", ())
.unwrap();
let after: String = tx.query_one("SELECT val FROM t WHERE id = 1", ()).unwrap();
assert_eq!(after, "orig", "snapshot saw updated value on point lookup");
let scan_val: String = tx
.query_one("SELECT val FROM t ORDER BY id LIMIT 1", ())
.unwrap();
assert_eq!(scan_val, "orig", "snapshot saw updated value on scan");
tx.rollback().unwrap();
db.close().ok();
}
#[test]
fn test_snapshot_isolation_cold_delete() {
let dir = tempfile::tempdir().unwrap();
let dsn = format!("file://{}", dir.path().to_str().unwrap());
let db = Database::open(&dsn).unwrap();
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, val TEXT)", ())
.unwrap();
db.execute("INSERT INTO t VALUES (1, 'a')", ()).unwrap();
db.execute("INSERT INTO t VALUES (2, 'b')", ()).unwrap();
db.execute("PRAGMA CHECKPOINT", ()).unwrap();
let mut tx = db
.begin_with_isolation(IsolationLevel::SnapshotIsolation)
.unwrap();
db.execute("DELETE FROM t WHERE id = 2", ()).unwrap();
let count: i64 = tx.query_one("SELECT COUNT(*) FROM t", ()).unwrap();
assert_eq!(count, 2, "snapshot lost deleted row");
let val: String = tx.query_one("SELECT val FROM t WHERE id = 2", ()).unwrap();
assert_eq!(val, "b", "snapshot can't read deleted row");
tx.rollback().unwrap();
db.close().ok();
}
#[test]
fn test_seal_proceeds_during_snapshot() {
let dir = tempfile::tempdir().unwrap();
let dsn = format!("file://{}", dir.path().to_str().unwrap());
let db = Database::open(&dsn).unwrap();
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, val INTEGER)", ())
.unwrap();
for i in 1..=200 {
db.execute(&format!("INSERT INTO t VALUES ({}, {})", i, i * 10), ())
.unwrap();
}
let mut snap = db
.begin_with_isolation(IsolationLevel::SnapshotIsolation)
.unwrap();
let count_before: i64 = snap.query_one("SELECT COUNT(*) FROM t", ()).unwrap();
assert_eq!(count_before, 200);
for i in 201..=250 {
db.execute(&format!("INSERT INTO t VALUES ({}, {})", i, i * 10), ())
.unwrap();
}
db.execute("PRAGMA CHECKPOINT", ()).unwrap();
let count_after: i64 = snap.query_one("SELECT COUNT(*) FROM t", ()).unwrap();
assert_eq!(
count_after, 200,
"snapshot should see 200 rows after checkpoint, not {}",
count_after
);
let count_auto: i64 = db.query_one("SELECT COUNT(*) FROM t", ()).unwrap();
assert_eq!(count_auto, 250);
let val: i64 = snap
.query_one("SELECT val FROM t WHERE id = 100", ())
.unwrap();
assert_eq!(val, 1000);
let new_row_count: i64 = snap
.query_one("SELECT COUNT(*) FROM t WHERE id > 200", ())
.unwrap();
assert_eq!(
new_row_count, 0,
"snapshot should not see post-snapshot rows"
);
snap.rollback().unwrap();
db.close().ok();
}
#[test]
fn test_snapshot_update_cold_then_reseal() {
let dir = tempfile::tempdir().unwrap();
let dsn = format!("file://{}", dir.path().to_str().unwrap());
let db = Database::open(&dsn).unwrap();
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, val TEXT)", ())
.unwrap();
for i in 1..=200 {
db.execute(&format!("INSERT INTO t VALUES ({}, 'v{}')", i, i), ())
.unwrap();
}
db.execute("PRAGMA CHECKPOINT", ()).unwrap();
let mut snap = db
.begin_with_isolation(IsolationLevel::SnapshotIsolation)
.unwrap();
db.execute("UPDATE t SET val = 'updated' WHERE id = 1", ())
.unwrap();
db.execute("PRAGMA CHECKPOINT", ()).unwrap();
let val: String = snap
.query_one("SELECT val FROM t WHERE id = 1", ())
.unwrap();
assert_eq!(
val, "v1",
"snapshot should see original 'v1', not 'updated'"
);
let auto_val: String = db.query_one("SELECT val FROM t WHERE id = 1", ()).unwrap();
assert_eq!(auto_val, "updated");
snap.rollback().unwrap();
db.close().ok();
}