Repository navigation
fix: route extended-protocol copy-in termination through Sync - #465
Merged
Merged
Conversation
After a successful extended-protocol COPY FROM STDIN, the connection stayed in `CopyInProgress(true)` state and the client's terminating Sync message was swallowed by the catch-all arm of the state matcher. `on_sync` therefore never ran, `ReadyForQuery` was never sent, and the connection deadlocked: clients built on rust-postgres/tokio-postgres complete the copy with CopyDone followed by Sync, so every extended copy-in froze the connection after its first batch. Two changes, both mirroring PostgreSQL: - after a successful `on_copy_done` in extended mode, transition the connection to `AwaitingSync` so the client's trailing Sync is dispatched to `on_sync`, which sends `ReadyForQuery` and returns the connection to normal operation (this is what the existing comment intended, but the state machine never made the Sync reachable); - a Sync received while the copy is still unfinished (no preceding CopyDone/CopyFail) is rejected with an 08P01 protocol violation, like PostgreSQL rejects any unexpected message type during COPY, instead of being silently discarded. Adds regression tests driving both query protocols over raw TCP: the extended round trip (Sync after CopyDone completes with ReadyForQuery and the connection serves further queries), the mid-copy Sync rejection with connection recovery, and the simple protocol round trip. Without the fix the extended tests fail by timeout, reproducing the deadlock. Signed-off-by: Ning Sun <sunning@greptime.com>
redox
added a commit
to altertable-ai/pgwire
that referenced
this pull request
Sep 28, 2026
rust-postgres pipelines a Sync right after the Execute that starts a COPY FROM STDIN, before any CopyData. Since sunng87#465 that Sync aborted the copy with 08P01, breaking every extended-protocol copy from that client. PostgreSQL ignores Flush and Sync in copy-in mode for exactly this reason. Co-authored-by: Cursor <cursoragent@cursor.com>
sunng87
pushed a commit
that referenced
this pull request
Sep 29, 2026
* fix: report the tracked transaction status after simple-protocol COPY FROM STDIN A successful simple-protocol CopyDone always answered ReadyForQuery(Idle), so a COPY run inside BEGIN made clients that track the transaction state from ReadyForQuery believe the transaction had ended. Co-authored-by: Cursor <cursoragent@cursor.com> * fix: ignore Flush and Sync during copy-in, like PostgreSQL rust-postgres pipelines a Sync right after the Execute that starts a COPY FROM STDIN, before any CopyData. Since #465 that Sync aborted the copy with 08P01, breaking every extended-protocol copy from that client. PostgreSQL ignores Flush and Sync in copy-in mode for exactly this reason. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
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.
We will only await for
SyncafterCopyDoneis sent from client. Will reject any other messages during the copy.