pub const SEED_LOG_INTEGRITY: &str = r#"
INSERT OR REPLACE INTO log_integrity (id, rows_removed)
SELECT 1, CASE
WHEN (SELECT COUNT(*) FROM transaction_log)
= COALESCE(
(SELECT seq FROM sqlite_sequence WHERE name = 'transaction_log'),
0)
THEN 0
ELSE 1
END
"#;Expand description
Compute CREATE_LOG_INTEGRITY_TABLE’s bit from the log itself (v16, D-249).
One statement, run by baseline and by the v15 -> v16 rung alike, because a
rule stated twice is a rule that can disagree with itself (D-035) — and
these two would have: a baseline log is empty, an upgraded one may have been
archived for years, and “empty” is exactly where the obvious test is wrong.
§The witness is sqlite_sequence, not MAX(seq_id)
transaction_log.seq_id is INTEGER PRIMARY KEY AUTOINCREMENT, so SQLite
keeps the high-water mark of every id it has ever allocated in
sqlite_sequence, and deleting rows does not lower it. A rolled-back
transaction rolls the counter back with it (D-049), so the mark is exactly
the number of rows the log has ever held. Therefore COUNT(*) = seq holds
if and only if nothing has left, whatever the shape of what left: interior
gaps, a raised floor, or every row at once.
That last one is why this is not the test temporal::replay used
before v16. MIN(seq_id) = 1 AND COUNT(*) = MAX(seq_id) is exact on a
non-empty log and says intact on an empty one, which is right for a
database that has never been written and wrong for one that has been fully
archived — the two states it cannot see apart. sqlite_sequence sees them
apart: no row for a young log, a positive mark for an emptied one.
OR REPLACE because the ladder re-runs rungs over a stamped-back database
and this one has to be idempotent. It is: the value is a function of the
log, not of what is already in the row.