Track a client's parameter changes on the server connection - #1299
Track a client's parameter changes on the server connection#1299IgorOhrimenko wants to merge 2 commits into
Conversation
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
|
Related: #1302 fixes a third way session state survives checkin — a client's SQL-level |
014ce39 to
5316acd
Compare
|
I don't think this is the right solution. We should implement handling |
A SET or RESET the client sends once a server is attached changes that server's session, but we never wrote it down. What we did instead was clear the whole parameter cache whenever a CommandComplete said RESET, which trades one problem for another: the cache is what tells us to undo the change for the next client, and a ROLLBACK undoes the RESET anyway. pg_dump -t <table> walks straight into it: SET search_path TO '', then RESET search_path inside its transaction, then ROLLBACK. Postgres brings the empty search_path back, the cache no longer mentions it, and the next client gets the connection with unqualified names silently broken. A SET has the same hole in the other direction: BEGIN, a query, SET statement_timeout, COMMIT — the setting stays on the server and nothing resets it for whoever comes next. So record the change where it happens. RESET now has the transaction handling SET always had (reset vs reset_transaction), so a rollback restores what it cleared and a commit makes it permanent, and the server connection keeps the same record its client does. The existing parameter diff then does the rest: the next client is handed a precise RESET for what it doesn't want, instead of a connection nobody dares reuse. The CommandComplete fallback stays for RESETs we don't see coming — with the query parser off, that is still all we have.
Runs against a database with a single server connection, so the next client always gets the connection the previous one used.
5316acd to
934edbd
Compare
|
Reworked along those lines — no dirty flag, the connection keeps track of its parameters.
Digging into it turned up a second hole the same mechanism closes, with no BEGIN;
SELECT 1; -- a server is ours from here on
SET statement_timeout TO '5s';
COMMIT;On The One thing I did not do: an autocommit |
Problem
A
SETorRESETthe client sends once a server is attached changes that server's session, but nothing wrote it down. What we did instead was clear the whole parameter cache whenever aCommandCompletesaidRESET— which trades one problem for another, because that cache is exactly what tells us to undo the change for the next client.pg_dump -t <table>walks straight into it:The
ROLLBACKundoes theRESET, so the emptysearch_pathis back on the server, but the cache no longer mentions it. The next client gets that connection and every unqualified name fails with42P01.A
SEThas the same hole in the other direction, and it needs nopg_dumpat all:On
mainthe next client seesstatement_timeout = 5s. Nothing resets it, because the connection's parameter cache never learned about it —link_clientonly ever recorded what the client had at checkout time.Fix
Record the change where it happens, instead of reacting to a tag afterwards.
RESETgets the transaction handlingSETalways had —resetvsreset_transaction, next toinsertandinsert_transaction— so a rollback restores what it cleared and a commit makes it permanent. That also fixes a smaller thing on the way: an autocommitRESETused to leave its old value inreset_paramsforever, so an unrelated transaction rolling back later would resurrect it.The server connection then keeps the same record its client does, and the existing parameter diff does the rest. The next client is handed a precise
RESET "search_path"for what it doesn't want, rather than a connection nobody dares reuse.The
CommandCompletefallback stays for RESETs we don't see coming: with the query parser off, that is still all we have.Testing
Parameters: rollback restores an in-transaction reset, a commit makes it permanent, and a reset outside a transaction is not resurrected by a later rollback.Server: a recorded reset survivesROLLBACKand still producesRESET "search_path"for the next client; a committed one produces nothing; a recordedSETis undone for the next client; resetting one parameter no longer forgets the others; an untrackedRESETstill clears the cache.integration/python/test_session_params_leak.py: thepg_dumpsequence, aSETcommitted after connecting, and a committedRESET. Verified to fail onmain(the first two) and pass here.RESET "search_path"when the connection is handed over — noRESET ALL, no churn.