feat(mssql): support native upsert via MERGE WITH (HOLDLOCK)#5794
feat(mssql): support native upsert via MERGE WITH (HOLDLOCK)#5794MarkusLund wants to merge 1 commit into
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds MSSQL native upsert support: enables NativeUpsert capability, extends the Merge AST with WHEN MATCHED and builders to construct MERGE from INSERT ... ON CONFLICT UPDATE, updates the Visitor API and MSSQL visitor to emit Changes
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. 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 |
c09666f to
4c0306b
Compare
There was a problem hiding this comment.
Pull request overview
This PR adds native upsert support for MSSQL by translating OnConflict::Update into MERGE ... WITH (HOLDLOCK) statements, providing atomic upsert semantics equivalent to PostgreSQL's and SQLite's ON CONFLICT DO UPDATE. This eliminates race conditions that previously existed with the transactional SELECT-then-INSERT/UPDATE fallback approach under concurrent load.
Changes:
- Enables
NativeUpsertcapability for the MSSQL connector and addsMerge::from_insert_with_update()to convertINSERT ... ON CONFLICT UPDATEintoMERGE ... WHEN MATCHED THEN UPDATE - Emits
WITH (HOLDLOCK)on all MSSQLMERGEstatements (bothDoNothingandUpdatepaths) and extracts a sharedbuild_using_query()helper to eliminate duplication - Extends test assertion helpers and adds comprehensive unit tests for the new MERGE generation (single unique, compound, schema-qualified, multi-row, conditions, returning, error cases)
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
psl/psl-core/src/builtin_connectors/mssql_datamodel_connector.rs |
Adds NativeUpsert capability flag for MSSQL |
quaint/src/ast/merge.rs |
Adds from_insert_with_update(), build_on_conditions_from_constraints(), and shared build_using_query() helper; adds when_matched field to Merge struct |
quaint/src/ast/insert.rs |
Updates doc comment for OnConflict to reflect MSSQL support |
quaint/src/visitor/mssql.rs |
Handles OnConflict::Update in compatibility_modifications, emits WITH (HOLDLOCK) and WHEN MATCHED THEN UPDATE SET in MERGE visitor; updates all existing test expectations |
quaint/src/tests/upsert.rs |
Adds mssql tag to integration upsert tests |
query-engine/connector-test-kit-rs/query-engine-tests/tests/new/native_upsert.rs |
Extends assertion helpers to detect MERGE INTO alongside ON CONFLICT |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
There was a problem hiding this comment.
Actionable comments posted: 2
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: c155a584-97dd-45cb-b89a-fda174b6e368
📒 Files selected for processing (6)
psl/psl-core/src/builtin_connectors/mssql_datamodel_connector.rsquaint/src/ast/insert.rsquaint/src/ast/merge.rsquaint/src/tests/upsert.rsquaint/src/visitor/mssql.rsquery-engine/connector-test-kit-rs/query-engine-tests/tests/new/native_upsert.rs
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: fda4f8bd-2030-4a62-ad60-8847a1479dc5
📒 Files selected for processing (3)
quaint/src/ast/merge.rsquaint/src/visitor.rsquaint/src/visitor/mssql.rs
aa89183 to
4a76627
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
c2ce504 to
3416f7e
Compare
Changes since last reviewSquashed all commits into a single clean commit addressing the review feedback:
All existing MSSQL visitor tests (79) pass, plus 10 new native upsert tests. |
Enable NativeUpsert capability for MSSQL by translating INSERT ... ON CONFLICT UPDATE into MERGE ... WITH (HOLDLOCK) statements, providing atomic upsert semantics equivalent to PostgreSQL's and SQLite's ON CONFLICT DO UPDATE. - Add Merge::from_insert_with_update() to convert INSERT with OnConflict::Update into MERGE with WHEN MATCHED THEN UPDATE - Emit WITH (HOLDLOCK) on all MSSQL MERGE statements for serializable isolation under concurrent load - Place WITH (HOLDLOCK) before table alias per T-SQL syntax rules - Use alias in ON clause when merge target is aliased - Extract shared build_using_query() helper to eliminate duplication between DoNothing and Update paths - Make Visitor::compatibility_modifications return Result to propagate errors from Merge construction instead of panicking
3416f7e to
a0f221c
Compare
Summary
Adds native upsert support for SQL Server by translating
OnConflict::UpdateintoMERGE ... WITH (HOLDLOCK), giving MSSQL the same atomic upsert semantics that PostgreSQL and SQLite already have viaON CONFLICT DO UPDATE.Motivation
Currently, MSSQL upserts fall back to a transactional query graph: a
SELECTto check existence, then either anINSERTorUPDATEdepending on the result. While wrapped in a transaction, this multi-step approach can still surface unique constraint violations under concurrent load because the gap between the read and the write is not fully serializable.MERGE WITH (HOLDLOCK)replaces this with a single atomic statement that holds a range lock during the match phase, eliminating the race condition entirely.WITH (HOLDLOCK)is applied at the MSSQLMERGEvisitor level, so it affects both the newOnConflict::Updatepath and the existingOnConflict::DoNothingpath. This is intentional: both MERGE variants benefit from serializable-level locking on SQL Server.Changes
NativeUpsertcapability for the MSSQL connectorMerge::from_insert_with_update()to convertINSERT ... ON CONFLICT UPDATEintoMERGE ... WHEN MATCHED THEN UPDATEMERGE ONpredicates from explicit conflict columns (compound keys supported)[dbo].[table]) in generatedONclausesWITH (HOLDLOCK)on all MSSQLMERGEstatementsbuild_using_query()helper to avoid duplication betweenDoNothingandUpdatepathsnative_upsert.rsassertion helpers to detectMERGE INTOin addition toON CONFLICTTest plan
cargo test -p quaint test_native_upsert --lib— unit tests for rendered SQL (single unique, compound, schema-qualified, multi-row, conditions, returning, error cases)cargo test -p quaint upsert -- --nocapture— SQLite integration passing locallyquery-engine-testsnative upsert suite)Summary by CodeRabbit
New Features
Documentation
Tests
Refactor