Skip to content

Close the connection when unnamed execute fails before BindComplete - #17

Merged
quinnj merged 2 commits into
JuliaDatabases:mainfrom
PingoLee:main
Sep 26, 2026
Merged

quinnj merged 2 commits into
JuliaDatabases:mainfrom
PingoLee:main

Conversation

@PingoLee

Copy link
Copy Markdown
Contributor

execute(conn, sql) and execute(conn, sql, params) can leave a dead connection open. The unnamed statement path sends Parse, Describe, Bind, Execute and Sync together, then reads ParseComplete, the statement description and BindComplete. PostgreSQL does not flush those replies until Execute finishes, so a connection lost during a long statement (a network drop, a pooler or proxy restart) fails in these reads. The EOFError escapes without closing the socket. isopen stays true, reconnect=true never reconnects, and every later call on the connection fails with EOFError.

This completes the rule from #2 for the unnamed path: an exception that escapes mid-response must either drain through ReadyForQuery or close the socket. The three reads now close the socket unless the exception is an Error. That is the same condition readprepareddescription uses, since an Error means the stream is at ReadyForQuery or the socket is already closed. A server error, such as a syntax error, still leaves the connection usable. An interrupt during these reads now also closes the socket, as in waitfor. The prepared statement path already behaved this way through waitfor. No public API or runtime dependency changes.

Validation:

  • New scripted-server tests in test/execute_fake_server.jl close the connection before ParseComplete, before ParameterDescription and before BindComplete. They check that the socket is closed, that the next call reports the closed connection, and that reconnect=true reconnects. A control checks that a server error before ParseComplete keeps the connection usable. With the previous method, the ParseComplete, BindComplete and reconnect cases fail. The ParameterDescription case and the server-error control pass either way.
  • Reproduced first against PostgreSQL 16.15 through a local TCP proxy closed during SELECT pg_sleep(2). The unnamed path, with and without parameters, left isopen == true and failed every later call, including with reconnect=true. The prepared path closed and reconnected.
  • Full suite without Docker: 3,362 checks pass on Julia 1.12.7 and 3,363 on Julia 1.10.12 (Linux x64). All pass with --threads=2 on 1.12.7.
  • CI on my fork at the same commit (12aae57): all test runs pass. Linux with Docker integration: 6,501–6,502 checks on Julia min/1/pre, PostgreSQL 14/15/17/18, and SCRAM and MD5 authentication. Windows and macOS: 3,362–3,363 checks. Only the Codecov upload failed, because the fork has no token.

🤖 Generated with Claude Code

PingoLee and others added 2 commits September 23, 2026 18:39
PostgreSQL does not flush the replies to Parse, Describe and Bind until
Execute finishes. A connection lost during a long unnamed statement
therefore fails while reading them, and the EOFError escaped with the
socket still open: isopen stayed true, reconnect never ran, and every
later call failed with EOFError.

Close the socket unless the exception is an Error, as
readprepareddescription does. A server error still leaves the connection
usable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…o-failure

CI: close-socket-on-unnamed-execute-io-failure

@quinnj quinnj left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Reviewed by AI] Reviewed b0d3993 against 3c4151e. No blocking findings. The new guard covers the missing ParseComplete/BindComplete failure paths while preserving connections after a fully drained server error.

I ran all 28 scripted-server checks on Julia 1.13 with two threads. Restoring the base exec_unnamed method made eight checks fail and two error; the ParameterDescription and recoverable-server-error controls still passed. I approved the waiting upstream CI run and monitored it to completion: all 16 checks are green at this head, including platform, PostgreSQL-version, authentication, documentation, and coverage checks.

@quinnj quinnj left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@quinnj
quinnj merged commit ed11c4e into JuliaDatabases:main Sep 26, 2026
16 checks passed
quinnj referenced this pull request Sep 28, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants