[PATCH] Extensible ReadyForQuery wire protocol message and C hook, for connection pools and WAIT FOR LSN

From: Hannu Krosing <hannuk(at)google(dot)com>
To: pgsql-hackers <pgsql-hackers(at)postgresql(dot)org>
Subject: [PATCH] Extensible ReadyForQuery wire protocol message and C hook, for connection pools and WAIT FOR LSN
Date: 2026-10-08 09:35:27
Message-ID: CAMT0RQSP2Qopgr+5Z5NH1wur17=2fs0VAn5v3F8TtyQEApCmAQ@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi hackers,

One of the persistent challenges for connection poolers (PgBouncer, pgpool-II,
Odyssey) and connection routers in transaction-pooling mode is determining
whether a backend connection is clean enough to be safely recycled back into
the pool without issuing expensive round-trip cleanup probes (such as
DISCARD ALL,
querying pg_prepared_xacts, or checking for active WITH HOLD cursors
or temporary
namespaces).

Similarly, with the introduction of replication wait commands (such as
WAIT FOR LSN / pg_wal_replay_wait()), proxies and clients wishing to achieve
causal consistency (read-your-own-writes across read replicas) need to know
the commit LSN of the transaction just completed on the primary backend without
incurring the round-trip overhead of an extra SELECT
pg_current_wal_insert_lsn().

To address this, the attached patch introduces an extensible ReadyForQuery ('Z')
frontend/backend wire protocol message format and a corresponding C hook
(ready_for_query_hook).

Key highlights:

1. GUC Parameter: ready_for_query_message
- Enum with values 'plain' (default) and 'rich'.
- Context PGC_USERSET with GUC_REPORT.
- When 'plain', the protocol message is completely unchanged (5-byte length).
- When 'rich', the message length header is expanded to include additional
length-prefixed key-value pairs:
[uint8 key_len][key_bytes][uint8 val_len][val_bytes].

QUESTION: do we want a more detailed setting, like
SET ready_for_query_message = "rich:THL"
to sent only these three?

2. Built-in Session State Indicators (in 'rich' mode):
- 'T': "1" if temporary tables/schemas are active, "0" otherwise
(O(1) check).
- 'H': "1" if active WITH HOLD cursors exist in the session, "0" otherwise.
- 'P': "1" if active 2PC prepared transactions exist, "0" otherwise.
- 'L': Last transaction commit LSN as text (from XactLastCommitEnd).

3. C Hook: ready_for_query_hook
- Declared as: typedef void (*ready_for_query_hook_type) (StringInfo buf);
- Extensions can register this hook and use ready_for_query_has_key()
and ready_for_query_append_kv() to add custom contextual metadata
(e.g., custom session flags, tenant tags, or replication state).

4. Protocol Compatibility:
- Unless you set ready_for_query_message=rich the protocol does not
change at all
- libpq (fe-protocol3.c) is updated so that clients ignore any trailing
extension bytes in ReadyForQuery messages if they receive them, ensuring
full forward and backward compatibility.

5. Tests & Documentation:
- Documentation added in doc/src/sgml/protocol.sgml and
doc/src/sgml/config.sgml.
- Test module src/test/modules/test_ready_for_query includes both
SQL regression
and TAP test suites validating standard/rich modes, startup options,
temp tables, cursors, 2PC, LSN, and hook injection.

The patch applies cleanly against current master. Feedback and suggestions are
welcome.

Regards,
Hannu Krosing

Attachment Content-Type Size
0001-Extend-ReadyForQuery-wire-protocol-message-and-provi.patch application/x-patch 31.2 KB

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Osama Abdul Qader 2026-10-08 09:37:32 Re: Regress test might fail due to deadlock between domain and alter_table
Previous Message Manu 2026-10-08 09:34:50 Re: Add a hint to the "WAL summaries are required" errors