Repository navigation
fix(retain): make document lock/upsert dialect-aware for Oracle (#1944) - #1952
Merged
Merged
Conversation
The retain document-ownership gate used a single `INSERT ... ON CONFLICT DO UPDATE ... RETURNING content_hash` upsert to create-or-lock the document row and read its prior hash. PostgreSQL runs this as-is, but the Oracle adapter rewrites `ON CONFLICT DO UPDATE` to a `MERGE`, which cannot carry a `RETURNING` clause. The rewritten statement returned no rows, so every retain 500'd with `DPY-1003: the executed statement does not return rows`, turning the `test-python-client-oracle` and `test-typescript-client-oracle` jobs red. Move the lock-and-read step behind `DataAccessOps.lock_document_for_write` so each backend implements it natively: - PG: the same single-statement upsert (DO UPDATE always takes the row lock, avoiding the old two-step deadlock). - Oracle: an idempotent insert (IGNORE_ROW_ON_DUPKEY_INDEX) followed by a `SELECT ... FOR UPDATE`, since MERGE can't RETURNING. Adds regression tests: PG functional coverage of the placeholder→hash transition and bank isolation, plus translator tests pinning the root cause (MERGE drops RETURNING) and the Oracle fallback's clean rewrite.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #1944. Retain returned 500
DPY-1003: the executed statement does not return rowson Oracle, turningtest-python-client-oracleandtest-typescript-client-oraclered.Cause
#1930 changed the retain document-ownership gate to a single-statement upsert:
PostgreSQL runs this as-is. The Oracle adapter rewrites
ON CONFLICT DO UPDATEto aMERGE— and OracleMERGEcannot carry aRETURNINGclause, so the rewritten statement returns no rows and thefetchvalfails withDPY-1003.Fix
Move the lock-and-read step behind a dialect-aware
DataAccessOps.lock_document_for_writemethod (mirrors the existing strategy pattern that keepsif backend_typechecks out of business logic):INSERT ... ON CONFLICT DO UPDATE ... RETURNING.DO UPDATEalways takes the row lock atomically, preserving fix(retain): pre-extraction freshness recheck + serialize concurrent same-doc writers #1930's deadlock fix.IGNORE_ROW_ON_DUPKEY_INDEX, the same idiom already used byenqueue_graph_maintenance) followed bySELECT content_hash ... FOR UPDATE. Concurrent same-document inserters block on the duplicate key until the holder commits, so writers still serialize.Both return the pre-existing hash (
'__pending__'for a freshly inserted row), driving the later-batch takeover check unchanged.Tests
tests/test_lock_document_for_write.py:(id, bank_id)isolation (runs in the default suite against pg).MERGEthat dropsRETURNING) and that the Oracle fallback'sSELECT ... FOR UPDATEtranslates cleanly.End-to-end Oracle coverage comes from the existing
test-*-client-oracleCI jobs that the issue reported failing.Scope
Only the broken
DO UPDATE ... RETURNINGsite is rerouted. The twoON CONFLICT DO NOTHING + SELECT FOR UPDATEsites (zero-facts / no-batch paths) already translate correctly on Oracle and are left unchanged.