Motivation
The helper currently hardcodes `_journal=WAL&_timeout=5000&_fk=true&_txlock=immediate` on every SQLite DSN. That's the right default for read-write databases, but for read-only databases it has two undesired consequences:
- It flips the file to WAL mode (`_journal=WAL` is unconditional in `sql/helper.go`), leaving `-wal` / `-shm` sidecars on disk for a file we never write to.
- It takes a write-capable lock even though we never write, which interacts badly with some filesystem-level replacement patterns (atomic renames, rsync snapshots) and prevents concurrent readers in edge cases.
Proposal
Add an opt-in read-only knob to `SQLiteOptions`:
```go
type SQLiteOptions struct {
Path string
ReadOnly bool
}
```
When `ReadOnly` is true, use a DSN along the lines of:
```
?mode=ro&immutable=1&_timeout=5000
```
- `mode=ro` — refuse any write attempts at the driver level.
- `immutable=1` — tell SQLite the file cannot change under us, disabling WAL creation and locking entirely. Suitable for any DB that behaves as an immutable snapshot (e.g. replaced via rename rather than modified in place).
`_fk` and `_txlock` don't apply to read-only connections and can be dropped.
Scope
Just the DSN change and option wiring. No behavioural change for existing callers (default stays read-write with WAL).
Motivation
The helper currently hardcodes `_journal=WAL&_timeout=5000&_fk=true&_txlock=immediate` on every SQLite DSN. That's the right default for read-write databases, but for read-only databases it has two undesired consequences:
Proposal
Add an opt-in read-only knob to `SQLiteOptions`:
```go
type SQLiteOptions struct {
Path string
ReadOnly bool
}
```
When `ReadOnly` is true, use a DSN along the lines of:
```
?mode=ro&immutable=1&_timeout=5000
```
`_fk` and `_txlock` don't apply to read-only connections and can be dropped.
Scope
Just the DSN change and option wiring. No behavioural change for existing callers (default stays read-write with WAL).