Skip to content

feat: implement PRAGMA synchronous (FULL/NORMAL/OFF) (#645) - #650

Merged
iheitlager merged 1 commit into
mainfrom
feat/645-pragma-synchronous
Aug 29, 2026
Merged

feat: implement PRAGMA synchronous (FULL/NORMAL/OFF) (#645)#650
iheitlager merged 1 commit into
mainfrom
feat/645-pragma-synchronous

Conversation

@iheitlager

Copy link
Copy Markdown
Member

Summary

  • PRAGMA synchronous was silently ignored (src/vdbe/pragma.rs had no handling), so every commit unconditionally did the fsyncs matching only stock SQLite's FULL default, with no way to opt into NORMAL/OFF.

  • Adds a full parser → AST → codegen → VDBE path, mirroring journal_mode's (pager: journal_mode=WAL switching #388) shape but bidirectional — the bare query form (PRAGMA synchronous, no =) is implemented too, unlike journal_mode's (still Unsupported).

  • Pager::flush_locked/flush_wal_locked now gate their three commit-time fsyncs on the active SynchronousMode, per the policy table in ADR-0036:

    Level Journal fsync (rollback) Main-file fsync (rollback) WAL frame fsync
    Full (default) yes yes yes
    Normal yes no no
    Off no no no
  • Architecture note: SynchronousMode lives in src/header.rs, not src/pager.rs (its otherwise natural home) — vdbe/pragma.rs needs to name it directly, and vdbe/ may never use crate::pager directly (spec 001-architecture Requirement 1, enforced by tests/unit/layer_isolation.rs). Same reason JournalMode already lives there.

  • Incidental fix: repl.rs's generic (non-SELECT) statement path was silently discarding any result rows a program emitted — meaning PRAGMA integrity_check's output was already being dropped, pre-existing and unrelated to this ticket, but fixed alongside it since synchronous's query form needed the same row-printing to be testable via the CLI at all.

  • MemoryVfs gained a sync_calls() counter (shared across clones/handles) so the new Pager fsync-gating tests can assert whether a commit actually fsynced — an in-memory backend has no other way to observe that.

Test plan

  • cargo test — full suite passes (975 lib tests + all integration suites, 0 failures)
  • cargo clippy --all-targets / cargo fmt --check — clean
  • make check-grammar-drift — clean (grammar EBNF extended with synchronous carve-out, tagged V7)
  • make assurance — no dead links introduced
  • Pager unit tests assert exact fsync counts per level, both rollback-journal and WAL commit paths
  • VDBE/codegen/parser unit tests for set + query forms, all three levels, case-insensitivity, unsupported values (ON/EXTRA/out-of-range ints — explicitly out of scope per the ticket)
  • Oracle-parity CLI test (tests/unit/pragma_synchronous_repl.rs) diffs our repl output against real sqlite3 for PRAGMA synchronous = <level>; PRAGMA synchronous; across OFF/NORMAL/FULL

Refs: #645

spend: matched estimate (medium)

🤖 Generated with Claude Code

Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com

PRAGMA synchronous was silently ignored, so every commit unconditionally
did the fsyncs that only match FULL (the default). Adds a full
parser/AST/codegen/VDBE path (mirroring journal_mode's #388 shape, but
bidirectional: the bare query form is implemented too, unlike
journal_mode's) and wires Pager::flush_locked/flush_wal_locked to skip
fsyncs per ADR-0036's policy table:

  Level    Journal fsync (rollback)  Main-file fsync (rollback)  WAL frame fsync
  Full     yes                       yes                         yes
  Normal   yes                       no                          no
  Off      no                        no                          no

SynchronousMode lives in src/header.rs (not src/pager.rs, its otherwise
natural home) so vdbe/pragma.rs can name it without violating spec
001-architecture Requirement 1 ("VDBE does not know file format" —
vdbe/ may never `use crate::pager` directly).

repl.rs's generic (non-SELECT) statement path previously discarded any
result rows a program emitted — meaning PRAGMA integrity_check's output
was silently dropped too, pre-existing and unrelated to this ticket but
fixed alongside it since the synchronous query form needs the same
row-printing to be testable via the CLI at all.

MemoryVfs gained a sync_calls() counter (shared across clones/handles)
so the new Pager fsync-gating tests can assert whether a commit
actually fsynced, which an in-memory backend has no other way to show.

spend: matched estimate (medium)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@iheitlager
iheitlager merged commit 63d58d1 into main Aug 29, 2026
6 checks passed
@iheitlager
iheitlager deleted the feat/645-pragma-synchronous branch August 29, 2026 20:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant