#![cfg(feature = "std")]
use graphitesql::vfs::memory::MemoryVfs;
use graphitesql::{Connection, Value};
fn scalar_i64(c: &Connection, sql: &str) -> i64 {
let r = c.query(sql).unwrap();
match &r.rows[0][0] {
Value::Integer(i) => *i,
other => panic!("expected integer, got {other:?}"),
}
}
fn ints(c: &Connection, sql: &str) -> Vec<i64> {
c.query(sql)
.unwrap()
.rows
.iter()
.map(|row| match row[0] {
Value::Integer(v) => v,
ref o => panic!("not int: {o:?}"),
})
.collect()
}
fn wal_three_conns() -> (MemoryVfs, Connection, Connection, Connection) {
let vfs = MemoryVfs::new();
{
let mut c = Connection::create_vfs(&vfs, "db", 4096).unwrap();
c.execute("PRAGMA journal_mode=WAL").unwrap();
c.execute("CREATE TABLE t(id INTEGER PRIMARY KEY, v INT)")
.unwrap();
c.execute("INSERT INTO t(v) VALUES (1)").unwrap();
}
let a = Connection::open_vfs(&vfs, "db").unwrap();
let b = Connection::open_vfs(&vfs, "db").unwrap();
let c = Connection::open_vfs(&vfs, "db").unwrap();
(vfs, a, b, c)
}
#[test]
fn sibling_sees_committed_wal_frames() {
let (_vfs, mut a, b, _c) = wal_three_conns();
assert_eq!(scalar_i64(&a, "SELECT count(*) FROM t"), 1);
assert_eq!(scalar_i64(&b, "SELECT count(*) FROM t"), 1);
a.execute("INSERT INTO t(v) VALUES (2),(3),(4)").unwrap();
assert_eq!(scalar_i64(&b, "SELECT count(*) FROM t"), 4);
assert_eq!(scalar_i64(&b, "SELECT sum(v) FROM t"), 10);
assert_eq!(
b.query("PRAGMA integrity_check").unwrap().rows[0][0],
Value::Text("ok".into())
);
a.execute("INSERT INTO t(v) VALUES (5)").unwrap();
assert_eq!(scalar_i64(&b, "SELECT sum(v) FROM t"), 15);
}
#[test]
fn open_reader_keeps_snapshot_across_writer_commits() {
let (_vfs, mut a, mut b, _c) = wal_three_conns();
b.execute("BEGIN").unwrap();
assert_eq!(scalar_i64(&b, "SELECT count(*) FROM t"), 1);
a.execute("INSERT INTO t(v) VALUES (2),(3)").unwrap();
assert_eq!(scalar_i64(&b, "SELECT count(*) FROM t"), 1);
assert_eq!(scalar_i64(&b, "SELECT sum(v) FROM t"), 1);
b.execute("COMMIT").unwrap();
assert_eq!(scalar_i64(&b, "SELECT count(*) FROM t"), 3);
assert_eq!(scalar_i64(&b, "SELECT sum(v) FROM t"), 6);
}
#[test]
fn many_frames_visible_to_sibling() {
let (_vfs, mut a, b, _c) = wal_three_conns();
for i in 2..=200 {
a.execute(&format!("INSERT INTO t(v) VALUES ({i})"))
.unwrap();
}
assert_eq!(scalar_i64(&b, "SELECT count(*) FROM t"), 200);
assert_eq!(scalar_i64(&b, "SELECT sum(v) FROM t"), 20100);
assert_eq!(
b.query("PRAGMA integrity_check").unwrap().rows[0][0],
Value::Text("ok".into())
);
assert_eq!(scalar_i64(&a, "SELECT count(*) FROM t"), 200);
assert_eq!(scalar_i64(&a, "SELECT sum(v) FROM t"), 20100);
}
#[test]
fn readers_correct_across_checkpoint() {
let (_vfs, mut a, b, mut c) = wal_three_conns();
a.execute("INSERT INTO t(v) VALUES (2),(3),(4)").unwrap();
assert_eq!(scalar_i64(&b, "SELECT sum(v) FROM t"), 10);
c.execute("PRAGMA wal_checkpoint").unwrap();
assert_eq!(scalar_i64(&b, "SELECT count(*) FROM t"), 4);
assert_eq!(scalar_i64(&a, "SELECT sum(v) FROM t"), 10);
assert_eq!(
b.query("PRAGMA integrity_check").unwrap().rows[0][0],
Value::Text("ok".into())
);
a.execute("INSERT INTO t(v) VALUES (10)").unwrap();
assert_eq!(scalar_i64(&b, "SELECT sum(v) FROM t"), 20);
assert_eq!(scalar_i64(&c, "SELECT count(*) FROM t"), 5);
assert_eq!(
c.query("PRAGMA integrity_check").unwrap().rows[0][0],
Value::Text("ok".into())
);
}
#[test]
fn checkpoint_does_not_strand_an_open_reader() {
let (_vfs, mut a, mut b, mut c) = wal_three_conns();
a.execute("INSERT INTO t(v) VALUES (2),(3)").unwrap();
b.execute("BEGIN").unwrap();
assert_eq!(scalar_i64(&b, "SELECT sum(v) FROM t"), 6);
a.execute("INSERT INTO t(v) VALUES (4),(5)").unwrap(); c.execute("PRAGMA wal_checkpoint").unwrap();
assert_eq!(scalar_i64(&b, "SELECT sum(v) FROM t"), 6);
assert_eq!(scalar_i64(&b, "SELECT count(*) FROM t"), 3);
b.execute("COMMIT").unwrap();
assert_eq!(scalar_i64(&b, "SELECT sum(v) FROM t"), 15);
assert_eq!(
b.query("PRAGMA integrity_check").unwrap().rows[0][0],
Value::Text("ok".into())
);
}
#[test]
fn late_opened_connection_adopts_shared_index() {
let vfs = MemoryVfs::new();
{
let mut c = Connection::create_vfs(&vfs, "db", 4096).unwrap();
c.execute("PRAGMA journal_mode=WAL").unwrap();
c.execute("CREATE TABLE t(id INTEGER PRIMARY KEY, v INT)")
.unwrap();
}
let mut a = Connection::open_vfs(&vfs, "db").unwrap();
a.execute("INSERT INTO t(v) VALUES (7),(8),(9)").unwrap();
let d = Connection::open_vfs(&vfs, "db").unwrap();
assert_eq!(ints(&d, "SELECT sum(v) FROM t"), vec![24]);
assert_eq!(
d.query("PRAGMA integrity_check").unwrap().rows[0][0],
Value::Text("ok".into())
);
}