7.9.35. SQL-34 — Backup, VACUUM, integrity check
This tutorial covers the maintenance / hygiene side of SQLite. Each
helper has a strict variant (panics on failure) and a try_* sibling
returning SqlError / Result<...> for non-panic recovery.
Helper |
What it does |
|---|---|
|
Defragment the file, reclaim deleted-row space. |
|
Snapshot the live DB to a new file (one-off copy, no source mutation). |
|
|
|
Full corruption scan. Returns |
|
Cheaper sibling of |
|
Online hot backup. Two overloads: into another open runner, or directly to a path on disk. |
7.9.35.1. End-to-end
require daslib/sql
require sqlite/sqlite_boost
[sql_table(name = "Logs")]
struct LogEntry {
@sql_primary_key Id : int
Severity : int
Message : string
}
[export]
def main {
with_sqlite(":memory:") $(db) {
db |> create_table(type<LogEntry>)
for (i in range(100)) {
db |> insert(LogEntry(
Id = i + 1,
Severity = (i % 4),
Message = "msg #{i}"))
}
// VACUUM ----------------------------------------------------
// Rewrites the file from scratch. After large DELETE
// workloads this reclaims free pages and packs surviving
// rows densely. Cannot run inside an active transaction ---
// the helper rejects that case before reaching SQLite.
db |> exec("DELETE FROM Logs WHERE Severity = 0")
db |> vacuum()
// OPTIMIZE -------------------------------------------------
// Cheap; recommended at connection close on long-lived
// connections. No-op when nothing has changed.
db |> optimize()
// INTEGRITY CHECK -----------------------------------------
let issues <- db |> integrity_check()
if (length(issues) == 1 && issues[0] == "ok") {
to_log(LOG_INFO, "integrity_check: db is healthy\n")
} else {
for (msg in issues) {
to_log(LOG_ERROR, " - {msg}\n")
}
}
}
}
7.9.35.2. VACUUM in a transaction returns Err
The strict form would panic mid-transaction; try_vacuum surfaces
the error so the caller can recover:
db |> with_transaction() {
let err = db |> try_vacuum()
if (err |> is_some) {
to_log(LOG_INFO, "try_vacuum mid-tx: {err |> unwrap}\n")
}
}
7.9.35.3. VACUUM INTO — file snapshot
VACUUM INTO '<path>' writes a one-off copy of the live DB to a new
file without touching the source. The path is single-quoted with
'' doubling — SQLite doesn’t accept ? binds for VACUUM:
db |> vacuum_into("/tmp/snapshot.sqlite")
db |> vacuum_into("with'apostrophe.sqlite") // quotes are escaped
Use vacuum_into when you want a defragmented snapshot. For a hot
copy of the live DB without re-packing, use backup_to (below).
7.9.35.4. Online hot backup — backup_to
The Backup API copies a live database into another open connection or
directly to disk. The destination receives the full state of the
source; transient SQLITE_BUSY / SQLITE_LOCKED responses
(concurrent writers on the source) are retried automatically with a
50 ms backoff.
Snapshot into another runner (e.g. an in-memory clone):
with_sqlite(":memory:") $(snapshot) {
db |> backup_to(snapshot)
// ... query `snapshot` to inspect a frozen view ...
}
Snapshot directly to disk (the file is opened, populated, and closed for you):
db |> backup_to("/tmp/hot_snapshot.sqlite")
The strict form panics on any non-completion; the try_ form
returns SqlError. backup_to replaces the destination
wholesale — pre-existing tables on the destination are gone after
the call.
7.9.35.5. Integrity check return shape
integrity_check returns array<string>:
["ok"]— the database is healthy.One row per detected issue otherwise (truncated file, missing index entry, dangling page chain, …).
The helper returns rows verbatim; the caller decides how to react.
quick_check has the same return shape but skips the per-index
cross-table walk — useful as a fast pre-flight before running the
full integrity_check.
7.9.35.6. Deferred
Backup progress callback.
sqlite3_backup_step(bp, N)returning remaining + pagecount, surfaced to a daslang block. Useful for long-running backups under a “saving…” progress bar.First-N rows for
integrity_check/quick_check. SQLite’s pragma accepts a row-cap argument (PRAGMA integrity_check(10)stops after 10 issues). The current helper always runs the full scan; add an optionalNonce a real consumer asks.
See also
Full source: tutorials/sql/34-backup_vacuum.das
Previous tutorial: SQL-33 — PRAGMA tuning
Next tutorial: SQL-35 — Streaming results with _each_sql