fix: flush implicit transaction before BEGIN IMMEDIATE (#135)#162
Open
azizur100389 wants to merge 1 commit intotirth8205:mainfrom
Open
fix: flush implicit transaction before BEGIN IMMEDIATE (#135)#162azizur100389 wants to merge 1 commit intotirth8205:mainfrom
azizur100389 wants to merge 1 commit intotirth8205:mainfrom
Conversation
When git diff includes deleted files, remove_file_data() DELETEs open an implicit DEFERRED transaction. The subsequent store_file_nodes_edges() call then fails with "cannot start a transaction within a transaction" because BEGIN IMMEDIATE cannot nest inside DEFERRED. Commit any pending implicit transaction before BEGIN IMMEDIATE. Add regression tests for both incremental_update and full_build paths.
18a9c1b to
bcb3dad
Compare
ghiemer
added a commit
to ghiemer/code-review-graph
that referenced
this pull request
Apr 10, 2026
…205#135, tirth8205#181) Python's sqlite3 with default isolation_level="" silently opens a DEFERRED transaction on the first DML statement. When remove_file_data() is called for stale/deleted files, the DELETE statements open an implicit transaction that is never committed. The subsequent store_file_nodes_edges() then executes BEGIN IMMEDIATE inside that already-open transaction, causing: sqlite3.OperationalError: cannot start a transaction within a transaction This affects both full_build (stale-file purge loop) and incremental_update (deleted-file handling). Fix: - graph.py: Add in_transaction guard before BEGIN IMMEDIATE in store_file_nodes_edges() to flush any pending implicit transaction - graph.py: Add public rollback() method to GraphStore - incremental.py: Commit after stale-file purge loop in full_build() - incremental.py: Commit after deleted-file removal in incremental_update() Tests: - test_store_after_remove_no_transaction_error (single remove → store) - test_store_after_multiple_removes_no_transaction_error (bulk removes → store) Closes tirth8205#135, tirth8205#181, relates to tirth8205#162, tirth8205#193, tirth8205#94 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
4 tasks
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
sqlite3.OperationalError: cannot start a transaction within a transactionwhen runningcode-review-graph updateon a repo wheregit diffincludes deleted files (sqlite3.OperationalError: cannot start a transaction within a transaction on update when git diff includes deleted files #135).store_file_nodes_edges()to commit any pending implicit transaction beforeBEGIN IMMEDIATE.incremental_updateandfull_buildcode paths.Root Cause
Python's
sqlite3with defaultisolation_level=""auto-begins aDEFERREDtransaction on the first DML. Inincremental_updateandfull_build,remove_file_data()issuesDELETEstatements for deleted/stale files, silently opening an implicit transaction. The subsequentstore_file_nodes_edges()then executesBEGIN IMMEDIATEinside that already-open transaction, which SQLite rejects.Fix
Check
self._conn.in_transactionbeforeBEGIN IMMEDIATEand commit any pending implicit transaction. This preserves atomic replace semantics while being robust against prior implicit transaction state. The guard is a no-op when no implicit transaction is open.Tests Added
test_store_after_remove_no_transaction_error— direct GraphStore unit testtest_incremental_deleted_and_modified_files— end-to-end incremental update with mixed deletes and modificationstest_full_build_stale_files_then_parse— end-to-end full build with stale file purgingTest Plan
test_graph.pyandtest_incremental.pytests pass (46/46)ruff checkclean on all changed files