Deallocate client prepared statements at checkin - #1302
Open
IgorOhrimenko wants to merge 2 commits into
Open
Conversation
pg_dump creates a SQL-level prepared statement, which currently survives checkin, so the next dump landing on the same server connection fails with "prepared statement already exists". Runs against a database with a single server connection, so the reuse is deterministic instead of depending on which connection the pool hands out.
IgorOhrimenko
force-pushed
the
fix-pg-dump-prepared
branch
from
August 3, 2026 06:37
b4b0243 to
060c331
Compare
This was referenced Aug 3, 2026
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
IgorOhrimenko
force-pushed
the
fix-pg-dump-prepared
branch
3 times, most recently
from
August 3, 2026 07:26
7e44d44 to
2c0b9ff
Compare
A client can create prepared statements with SQL (PREPARE ... AS ...). Those belong to its session, but in transaction pooling the server connection goes back into the pool at the end of the transaction, taking them along. The next client that gets it collides on the name. pg_dump hits this every time: it prepares "dumpFunc", so the second dump through the pooler fails with 'prepared statement already exists' — the first one works only because it gets a connection nobody dumped on yet. Treat them like the other session state we already clean up and run DEALLOCATE ALL at checkin. A connection can need this alongside a parameter reset, so cleanup queries are now composed instead of picked from mutually exclusive branches. With the statements dropped, re-reading them from pg_prepared_statements at checkin only ever returned an empty set, so that round trip is gone and the flag it cleared is cleared by the cleanup itself.
IgorOhrimenko
force-pushed
the
fix-pg-dump-prepared
branch
from
August 3, 2026 07:37
2c0b9ff to
ed1c2d2
Compare
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.
Problem
pg_dumpprepares a statement with SQL (PREPARE dumpFunc(pg_catalog.oid) AS ...). In transaction pooling the server connection goes back into the pool at the end of the transaction and takes that statement with it, so the next dump that lands on the same connection fails:The first dump usually works — it gets a connection nobody has dumped on yet — which is what makes this look intermittent. With a single-connection pool it fails on the second dump, every time.
Reproduction:
Fix
Run
DEALLOCATE ALLat checkin when the client prepared statements with SQL — the connection already tracks that insync_prepared. Session-mode clients are unaffected: they keep the connection and already getDISCARD ALLwhen they leave.Cleanup queries are now composed rather than picked from mutually exclusive branches: a connection can need both a parameter reset and a deallocate (
RESET x; PREPARE y ...in one checkout), and the oldelse ifchain silently dropped the second one.Two follow-ons from that:
pg_prepared_statementsat checkin only ever returned an empty set, so that round trip and the method behind it are gone; the flag it cleared is cleared by the cleanup itself.Not touched here:
prepared_syncinpgdog-statsis no longer incremented by anything. Removing it reaches into public structs of that crate, so it seemed better left to a separate change.Testing
integration/python/test_pg_dump.py: three dumps in a row must all succeed, and a statement prepared on a connection that also needs a parameter reset must not outlive its client's checkin. Runs against a database with a single server connection, so the reuse is deterministic. Verified to fail onmain(8 runs out of 8) and pass with this branch.pg_dumpdoes.pg_dump -t <table>both clean, noprepared statement already existsin application logs afterwards.Related: #1298 and #1299 fix the other two ways session state survived checkin (an untracked
set_config, and aRESETrevived by rollback). Same class of bug, independent code paths.