Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ Transaction cleanup failures propagate as errors rather than being logged and ig
- **Attached-database observation no longer requires the main database to be observed too.** The whole observable acquisition path was gated on the *main* database's broker, so a write through an unobserved database into an observed `readWrite` attachment registered no hooks at all and reached that attachment's own subscribers not at all — silently, with every call reporting success. This was the same class of defect as #53 itself: observation depending on the wrong object. The observable path is now taken when *any* participating database is observed — main or a `readWrite` attachment — and `main` is simply omitted from the alias → broker map when the main database has no broker of its own, so its changes are dropped rather than misattributed. Nothing had covered this configuration, because the attached-observation tests enabled observation on both databases.
- **Known limitation:** a writer holds the broker it bound at acquisition for its whole lifetime, so a `disable_observation()` + `enable_observation()` cycle *during* an open transaction leaves that transaction publishing to the previous broker. Subscribers created before the cycle still receive its commit (the hook context keeps that broker alive); subscribers created after the cycle do not, while `is_observing()`, `subscribe()`, and the commit itself all report success. Reachable as: the last window `unobserve()`s and then `observe()`s again while another caller's interruptible transaction is still open. Pinned by an `#[ignore]`d test rather than only prose; the fix (reviving the slot's previous broker, gated on a lease held for the hooks' lifetime) is follow-up work.
- **Known limitation:** the plugin's `observe()`/`unobserve()` reference count is keyed on webview labels, so a Rust caller that enabled observation directly on a `DatabaseWrapper` is outside it. The last window releasing tears observation down database-wide and silently ends that caller's subscription; conversely a Rust `disable_observation()` breaks every window's live subscription while leaving their registrations non-zero. A plugin-level API for Rust observers is follow-up work.
- **A change notification now means that the change is durable and readable, not only that the commit hook ran.** SQLite's commit hook runs before the commit is final. It is the hook whose non-zero return converts a `COMMIT` into a `ROLLBACK`. A subscriber that read immediately after notification previously saw pre-commit state through another connection, on most notifications. The tests `a_notification_means_the_change_is_readable_in_wal_mode` and `a_notification_means_the_change_is_readable_in_rollback_journal_mode` now guard this, one per journal mode. The commit hook now converts and holds the transaction's changes and does not publish them yet. A hook registered with `SQLITE_TRACE_PROFILE` and `SQLITE_TRACE_STMT` publishes the changes when the statement that committed finishes, or when the next statement starts. By then the commit is durable, so any connection can read it. The writer does nothing extra.
- **A change notification now means that the change is durable and readable, not only that the commit hook ran.** SQLite's commit hook runs before the commit is final. It is the hook whose non-zero return converts a `COMMIT` into a `ROLLBACK`. A subscriber that read immediately after notification previously saw pre-commit state through another connection, on most notifications. The test `a_notification_means_the_change_is_readable` now guards this, with one case per journal mode (`wal_mode` and `rollback_journal_mode`). The commit hook now converts and holds the transaction's changes and does not publish them yet. A hook registered with `SQLITE_TRACE_PROFILE` and `SQLITE_TRACE_STMT` publishes the changes when the statement that committed finishes, or when the next statement starts. By then the commit is durable, so any connection can read it. The writer does nothing extra.
- **Notification order is now per connection.** Publication happens after SQLite released the write lock, so two connections that commit in one order can notify in the other. On master, the commit hook published under the lock, which kept commit order across connections. Every write through `sqlx-sqlite-conn-mgr`'s single writer, and so every write through the plugin, keeps its order.
- **A commit made during a statement reset notifies when the next statement starts.** `fetch_one` stops at the first row and resets the statement, and for an autocommit `INSERT ... RETURNING` the commit happens inside that reset, after SQLite's profile event. The trace hook is therefore also registered for `SQLITE_TRACE_STMT`, which fires when a statement starts, before any of its hooks. Without it, the held change waited for the next statement's profile event, and a failed next statement's rollback hook discarded it: the row was committed and no notification ever arrived. The test `a_commit_made_during_a_statement_reset_survives_a_later_failed_write` guards this. Dropping the connection also publishes it, guarded by `dropping_a_connection_publishes_a_commit_made_during_a_statement_reset`.
- The trace hook occupies the connection's one `sqlite3_trace_v2` slot. sqlx does not use that slot. If a consumer installs a trace hook on an observed connection, the new hook replaces this crate's hook, and notifications from that connection stop.
Expand Down
54 changes: 45 additions & 9 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,4 @@ tauri-plugin = { version = "2.7.1", features = ["build"] }
tauri = { version = "2.12.0", features = ["test"] }
tempfile = "3.23.0"
tokio = { version = "1.48.0", features = ["rt-multi-thread", "macros"] }
rstest = { version = "0.28.0", default-features = false }
1 change: 1 addition & 0 deletions crates/sqlx-sqlite-conn-mgr/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ libsqlite3-sys = "0.35.0"

[dev-dependencies]
tempfile = "3.24.0"
rstest = { version = "0.28.0", default-features = false }
Loading
Loading