fix: use a unique name for each nested savepoint - #18236
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
💤 Files with no reviewable changes (1)
Included review availability: Your plan includes up to 10 reviews per rolling hour; 9 remain after this review. 📝 WalkthroughWalkthroughThis PR changes nested savepoint naming to use a fresh dialect-generated transaction ID for each savepoint. It also adds a regression test that verifies nested savepoints receive distinct names. ChangesNested savepoint name collision fix
Estimated code review effort: 2 (Simple) | ~12 minutes Merge Risk: ⚪ Minimal · up to This localized change gives nested savepoints distinct names and adds regression coverage for the collision; no actionable merge-blocking risk remains beyond normal checks and review. Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Nested savepoint names were derived from a per-parent counter
(`${id}-sp-${parent.savepoints.size}`), so the first savepoint at every
nesting level collided on the same name (e.g. `<id>-sp-0`). `ROLLBACK TO
SAVEPOINT` resolves to the most recently declared savepoint of that name,
so a rollback could target the wrong savepoint. Give each savepoint a
fresh unique id instead.
f470490 to
20975e0
Compare
|
@WikiRik would you mind taking a look at this when you have some time? All checks are green and it's a fairly small diff. |
|
Just a heads up that this was sitting behind main, which I think is why it never went anywhere after the approval — GitHub was reporting it as out of date rather than mergeable. I've updated the branch, CI is green again and SippieCup's approval carried over, so it should be ready to go whenever someone has a minute. |
|
@MahinAnowar It's a fairly straight forward commit, but I would still like to have @WikiRik give his blessing on it. just in case i am missing something. |
WikiRik
left a comment
There was a problem hiding this comment.
Some comments that can be cleaned up. I think we can keep the one in transaction.ts.
Interesting that we didn't use #savepoints more, I'll do a sanity check before I approve what I can find back about that
|
Took all three, they're gone. Kept the one in |
|
@WikiRik when you get a moment — @SippieCup wanted your read on this one before it goes in. Your three suggestions are applied, so the only comment left in the test is the one in |
|
this can be merged, Still will defer to @WikiRik :) |
Issue
Fixes #18207 (Bug 1 — the one still present on
main/v7).When nesting transactions with
TransactionNestMode.savepoint, each savepoint's name was derived from a per-parent counter:Because the counter resets for every parent, the first savepoint at every nesting level gets the same name (e.g.
<id>-sp-0). Postgres (and others) resolveROLLBACK TO SAVEPOINT <name>to the most recently declared savepoint of that name, so a rollback at one level could silently roll back to a deeper savepoint — committing writes that should have been undone. A maintainer confirmed the issue and favoured generating a fresh id per savepoint.Fix
Give each savepoint a fresh unique id from the dialect's
generateTransactionId()(the same generator already used for root transaction ids), instead of a per-parent counter. The now-unused#savepointsmap (its only purpose was the counter) is removed.this.idstill tracks the root transaction (used for the connection uuid); only the savepoint#namechanges.Tests
Added a unit test in
packages/core/test/unit/transaction.test.ts(no DB — the existingqueryRawstub harness): it opens two levels of nestedsavepoint-mode transactions and asserts the two emittedSAVEPOINTstatements use distinct names. Verified it fails on the previous code (expected 1 to equal 2— both savepoints shared<id>-sp-0) and passes with the fix. ESLint + Prettier clean.Summary by CodeRabbit