Skip to content

Preserve enclosing transactions with nested savepoints - #245

Merged
quinnj merged 3 commits into
mainfrom
feat/savepoint-transactions
Oct 27, 2026
Merged

quinnj merged 3 commits into
mainfrom
feat/savepoint-transactions

Conversation

@quinnj

@quinnj quinnj commented Sep 26, 2026 •

Copy link
Copy Markdown
Member

Calling DBInterface.transaction inside a transaction started with SQL currently sends another START TRANSACTION, which commits the caller's earlier work. A later caller rollback cannot undo those rows. Use the server transaction status after draining pending results to choose a savepoint for an existing transaction. Nested helper calls and prepared executemany then compose without committing their enclosing scope.

Keep the connection locked and restore its previous task owner. If rollback or savepoint cleanup fails, close the uncertain session and report both the original and cleanup errors. Reuse the existing connection token sequence for reserved _mysqljl_ savepoint names; no new dependency, export or connection field.

MySQL statements that implicitly commit, including table creation in MySQL.load, and explicit transaction controls inside the callback remain outside this guarantee. The docs state those boundaries.

Validation:

  • Real MySQL 8.4.11 reproduces three failures on pristine main on both Julia 1.10.12 and 1.13.0; the same six controls pass with the fix. The permanent public workflow covers manual/implicit outer transactions, three-level nesting, caught inner errors, prepared-batch rollback and caller rollback.

  • Full minimum-version suite: 2,267 assertions, including MySQL 8.4 and MariaDB 11.4 live workflows and lifecycle soak. Current protocol suite: 1,900 assertions. Heavy unrelated scan-performance gates were disabled. Strict documentation and independent Astra source review pass.

  • The actual safe-trim executable passes seven runtime controls with code generation disabled, including nested transactions and failed rollback cleanup. Runtime-schema column materialization remains outside that fixture's supported subset.

  • Eight matched warm-cost processes retain exactly the same allocations for ordinary top-level transactions on both runtimes: 704/832 bytes for empty/ping callbacks on current, 864/1,024 on minimum. Local timing remains within the paired variation. Separate first-use controls show a 5–13 ms increase per new callback shape, primarily compilation; this is a correctness/composition change, not a speedup claim.

  • Hosted CI at 49acd08: all 15 applicable checks green, including Docker integration and all platform/version lanes; 2 scheduled-only gates skipped.

Co-authored by Codex

quinnj and others added 3 commits September 26, 2026 08:11
A deadlock makes the server roll back the whole transaction, savepoints
included. A nested DBInterface.transaction then failed its ROLLBACK TO
SAVEPOINT with 1305 (savepoint does not exist), treated the healthy
session as uncertain, and closed it, so a retryable deadlock cost the
caller its connection. A missing savepoint now means there is nothing
left to undo at that level: the original error propagates and the
connection stays open. Other rollback failures still close it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@quinnj
quinnj merged commit b4b8b34 into main Oct 27, 2026
17 checks passed
@quinnj
quinnj deleted the feat/savepoint-transactions branch October 27, 2026 11:12
@quinnj quinnj mentioned this pull request Oct 27, 2026
quinnj referenced this pull request Oct 27, 2026
Co-authored-by: Claude Opus 5.5 <[email protected]>
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