Repository navigation
Native: a created or updated record reads its row in the statement's crossing (closes #317) - #329
Merged
Merged
Conversation
…ing of the statement (#317) The create path read the row it always reads with a second crossing (arcadedb_n_next_bin after arcadedb_n_cmd). It now uses the form of arcadedb_n_exec whose reply carries the first rows, and so do the two UPDATE forms of save(). The stale-record check stays: an UPDATE's own reply comes after the write. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… form (#317) A CI run showed that an INSERT or UPDATE error is raised by the call in both forms, not when the row is read. The test pins that the two forms agree, and a SELECT run as a command pins the read-time case for both. The helper's docstring states the timing. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This was referenced Nov 10, 2026
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.
Closes #317. Part of #315 and the glue changes of the wheels-only 26.11.1.post1. Nothing changes for users: the records, their values and the error messages are those of the lazy form, and the test below compares them with it.
What changes: on the native wheel,
save()of a new record andVertex.new_edgerun their statement with the lazy command form (arcadedb_n_cmdreturns a cursor id) and then read the one row they always read with a second crossing (arcadedb_n_next_bin). They now call a privateNativeDatabase._command_first_row, which iscommandthrough the existing form ofarcadedb_n_execwhose reply already carries the first rows (the lazy bit of its flags left off), so a create is one crossing instead of two.save()of a saved record uses the same form for both of its UPDATE statements (the exact one and theRETURN AFTERone), so an update is three crossings instead of four. Publiccommandis unchanged and keeps the lazy form for every other caller. Both forms run the same Java code to pull the rows; error timing is the same on both forms: an error the engine raises while it runs the statement (anINSERTorUPDATE, whichsave()sends) is raised by the call, as bycommand, and one met while rows are computed lazily (aSELECTrun as a command) comes in the reply asrerrand is raised when the row is read, as before. Publiccommandis unchanged.The stale-record check is not read from the update's own result, and I kept it as it was. The engine's reply to an
UPDATEcomes after the write, andsave()promises that it writes nothing when the stored record changed. A before-image fromRETURN BEFOREwould only show the conflict after the caller's transaction already holds the write, so it would change what a caller that catches the error sees. The SELECT and theis_transaction_activecrossing stay.Peak memory does not rise: a create drops a cursor and a call, the reply holds the same one row.
Tests (
tests/test_native_one_row_crossings.py, native backend only): spies on the ctypes doors (cmd,call,call_bin,exec_queryand the batched cursor close) count the crossings of onesave()(create: one, also with a float array, which takesarcadedb_n_exec_bin), onenew_edgewith and without properties, and one update (three, for the exact and for the read-back form). They fail on the old code, which makes two and four. Oracles on the old behaviour: every created record (ints, text, non-ASCII, date and time, decimal, list and map, float array, nothing) is compared with the record the lazy statementINSERT INTO D CONTENT :rowreturns and with a lookup by RID; a unique-key violation raises the same message and class as the lazy form; a stale record is still refused withConcurrentModificationExceptionand writes nothing; an update outside a transaction still raises before any read. Added after review: abefore_createveto on a new record (no error, no record id, nothing stored, one crossing, and the same object saves once the veto is lifted), abefore_updateveto on both UPDATE forms (nothing written, three crossings, and the next save is no conflict), a statement error (a division by zero in anINSERTand anUPDATE: same timing, message and class as the lazy form, raised by the call in both, as a CI run showed) and a row error (aSELECTrun as a command: raised when the row is read, by both forms, with theReading the result set failed:message), and abefore_createcallback that raises.tests/test_native_statement_texts.pyandtests/test_native_save_baseline.py(statement texts and the number of copies) are untouched and must pass, and so musttests/test_cross_wheel_golden.py. I could not run any of it here (CI only); the runs are listed below.No speed claim: the measurement is a later laptop A/B, and the untimed profile studies queued for tonight. I did not touch
lookup_by_rid, which keeps the record id in its SQL text (#229).🤖 Generated with Claude Code