Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix a bunch of SQLite-related bugs #2866

Merged
merged 8 commits into from
Oct 10, 2024
Merged

Fix a bunch of SQLite-related bugs #2866

merged 8 commits into from
Oct 10, 2024

Conversation

kentonv
Copy link
Member

@kentonv kentonv commented Oct 8, 2024

  • Fix bug where if executing a prepared statement threw (e.g. due to violating a uniqueness constraint), the prepared statement would be permanently broken. (Note we have decided not to make the prepared statement API public, but this bug affected an experimental user.)
  • Fix bugs where if the _cf_KV or _cf_METADATA tables were created during a transaction which ended up being rolled back, then the in-memory state could be wrong, resulting in further access doing the wrong thing.
  • Throw a more descriptive error message when the user tries to execute BEGIN TRANSACTION. The "not authorized" error confused people into thinking that transactions weren't supported!
  • Add missing RELEASE of savepoints in transactionSync(), although in practice I think it didn't cause any actual problem (see commit description).

src/workerd/util/sqlite.c++ Outdated Show resolved Hide resolved
src/workerd/util/sqlite.c++ Outdated Show resolved Hide resolved
src/workerd/util/sqlite.c++ Outdated Show resolved Hide resolved
src/workerd/util/sqlite.c++ Outdated Show resolved Hide resolved
src/workerd/util/sqlite-test.c++ Show resolved Hide resolved
@kentonv
Copy link
Member Author

kentonv commented Oct 10, 2024

…ly threw.

`Query`'s destructor didn't run in this case, so the statement was never reset, and trying to use it again would fail with SQLITE_MISUSE.
We are doing other per-statement cleanup in `destroy()`, makes sense to reset row counters here too, rather than on the next query constructor.
This commit has no functional change, but changes prepareSql() to return a struct containing the statement and other information which must be kept with the statement. At present there is no other information, but the next commit will add a description of the statement's effects on the transaction stack.

I split this into a separate commit because it's a noisy mechanical change, which I wanted to keep separate from the actual logic change.
This registers a callback which will be called if the current transaction scope ends up being rolled back. We'll need this to fix bugs elsewhere.

The implementation requires that we keep track of the transaction stack, which is a bit of a pain. We can discover which statements affect the transaction stack via the authorizor callback.
The state of the `SqliteKv` object could get out-of-sync in the case of rollbacks. Our new `onRollback()` function makes this easy to deal with.
Also if cached alarm changes are rolled back.

This replaces the previous invalidation mechanism, which did not properly handle `transactionSync()`. The new mechanism handles all rollbacks, so we don't need the old mechanism at all anymore.
…ION.

People mistakenly believed that we didn't support transactions!
`ROLLBACK TO` does not release the savepoint, just rolls back to the point immediately after the savepoint was created. We must additionally release it.

This never caused a problem becaues:
1. `transactionSync()` always runs inside an implicit transaction. Committing or rolling back the implicit transaction implicitly releases all the savepoints.
2. It turns out SQLite allows savepoints with the same name as previous ones. The name always refers to the most-recent savepoint by that name which hasn't been released. So, the "leaked" savepoint didn't prevent a new savepoint with the same name from being created later.

Note that the async version of `transaction()` does release savepoints properly.

I also added a TODO to take advantage of the fact that savepoints can have the same name...
@kentonv
Copy link
Member Author

kentonv commented Oct 10, 2024

windows build failure unrelated; fixed in #2891

@kentonv kentonv merged commit 2fdf284 into main Oct 10, 2024
12 of 13 checks passed
@kentonv kentonv deleted the kenton/sqlite-bugs branch October 10, 2024 17:20
kentonv added a commit that referenced this pull request Oct 11, 2024
…dy in a transaction?`

Bug introduced in #2866. See comments for explanation.
kentonv added a commit that referenced this pull request Oct 11, 2024
…dy in a transaction?`

Bug introduced in #2866. See comments for explanation.
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.

4 participants