Skip to content

Release savepoints after rollback - #1367

Merged
jberkel merged 4 commits into
stephencelis:masterfrom
ShiroKSH:fix/release-rolled-back-savepoints
Aug 29, 2026
Merged

jberkel merged 4 commits into
stephencelis:masterfrom
ShiroKSH:fix/release-rolled-back-savepoints

Conversation

@ShiroKSH

Copy link
Copy Markdown
Contributor

Summary

  • release a savepoint after rolling it back
  • keep rollback and release as separate SQLite statements
  • cover nested cleanup and successful transaction reuse after a rollback

Root cause

ROLLBACK TO SAVEPOINT rewinds database changes but leaves the savepoint active. The connection therefore remained inside a transaction after a throwing outermost savepoint block, causing the next transaction to fail with cannot start a transaction within a transaction.

Impact

Failed savepoint blocks now leave the connection ready for subsequent transactions. Normal transaction and successful savepoint behavior are unchanged.

Validation

  • git diff --check
  • targeted SQLite state-transition reproduction for nested rollback/release cleanup and subsequent transaction reuse

@ShiroKSH
ShiroKSH marked this pull request as ready for review July 11, 2026 14:15
@ShiroKSH

Copy link
Copy Markdown
Contributor Author

@stephencelis We'd appreciate it if you could take a look at this pull request when you have a chance.

@jberkel

jberkel commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Thanks for your contribution, will look at it soon

@ShiroKSH

ShiroKSH commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

Hi maintainers, this PR has been open for over two weeks. When you have a moment, I would appreciate a review. Thank you.

@jberkel

jberkel commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator

Can you get the build green first? there are some lint errors.

@ShiroKSH

ShiroKSH commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

Fixed in ed1bd70. I moved the internal transaction helper into a Connection extension so the class stays within SwiftLint's type-body limit; behavior is unchanged. CI is running again.

@ShiroKSH

ShiroKSH commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

The CI setup fix is pushed in ac903cc. GitHub is waiting for maintainer approval before it can run workflows for the updated fork branch. Could you approve and run the workflow when convenient?

@jberkel

jberkel commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the tuist fix

@jberkel

jberkel commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Not sure why the SPM integration tests now fail. Perhaps an update of the macos-15 image (unfortunately these can't be pinned). I'm travelling at the moment and don't have always access to wifi, but will look at this later.

@ShiroKSH

Copy link
Copy Markdown
Contributor Author

CI follow-up pushed in 99b5938.

The earlier macOS 15 SPM SIGKILL was runner-specific: the current #1372 run passes the SPM integration step on both macOS 15 and macOS 26. The remaining Tuist failure comes from SwifterPM expecting Tuist/Package.resolved while Swift 6.2 no longer creates it for this package graph. The new commit uses Tuist's supported TUIST_USE_SWIFTERPM=0 fallback, avoiding toolchain-dependent lockfile generation.

The new workflow is waiting for maintainer approval. Could you approve and run it when convenient?

@jberkel

jberkel commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

From the sqlite.org docs (https://sqlite.org/lang_savepoint.html)

Instead of cancelling the transaction, the ROLLBACK TO command restarts the transaction again at the beginning. All intervening SAVEPOINTs are canceled, however.

just a clarification, so basically RELEASE acts as an empty "commit" which just closes the open transaction? but since there's been ROLLBACK TO nothing actually changes?

@ShiroKSH

Copy link
Copy Markdown
Contributor Author

Exactly. ROLLBACK TO undoes every change made after the named savepoint, but leaves that savepoint itself active on SQLite's transaction stack. The following RELEASE removes the now-reset savepoint so the failed Swift closure does not leave an open transaction behind.

For a savepoint nested inside an outer transaction, RELEASE only removes/merges that marker; it does not commit the outer transaction or write anything independently. If this is the outermost savepoint, RELEASE ends the restarted transaction, but the failed closure's changes have already been undone by ROLLBACK TO, so there is nothing from that closure to persist.

That is also why the sequence must be both statements rather than only ROLLBACK TO: SQLite explicitly says the matching savepoint remains on the stack after the rollback. https://sqlite.org/lang_savepoint.html

@jberkel
jberkel merged commit 321a218 into stephencelis:master Aug 29, 2026
4 checks passed
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.

2 participants