Set Notice Receiver Before libpq Connection Startup — May 2026 Summary
Problem
PostgreSQL's libpqsrv infrastructure (used by dblink, postgres_fdw, and other extensions for outbound libpq connections from within a backend) had a timing bug: the libpqsrv_notice_receiver callback — which routes remote NOTICE/WARNING messages through ereport() — was only installed after libpqsrv_connect() completed. Notices generated during connection establishment (e.g., from login event triggers on the remote server) bypassed structured logging and were dumped raw to stderr.
This broke the contract of the recently committed "Log remote NOTICE, WARNING, and similar messages using ereport()" feature.
Solution: Two-Phase Connection API
After an initial wrapper-function approach (V1) was rejected as too narrow, the accepted design splits libpqsrv_connect() into composable primitives:
-
libpqsrv_connect_start()/libpqsrv_connect_params_start()— Callslibpqsrv_connect_prepare()(which doesAcquireExternalFD()) thenPQconnectStart(). ReturnsPGconn*in a started-but-not-completed state. -
libpqsrv_connect_complete()— Drives the async connection to completion (polling withWaitLatchOrSocket, handling interrupts).
Between these two calls, callers can invoke PQsetNoticeReceiver() or any other per-connection configuration. The existing libpqsrv_connect() convenience functions remain for callers that don't need the hook point.
Key Design Constraints
- Resource cleanup contract:
libpqsrv_connect_complete()must always be called (even ifPQconnectStart()returns NULL) becauseAcquireExternalFD()already reserved an FD slot. - Double-free prevention: postgres_fdw uses a separate
start_connvariable, only assigning toconnafterlibpqsrv_connect_complete()succeeds. This prevents both the inner (libpqsrv_connect_complete'sPG_TRY/PG_CATCH) and outer (connect_pg_server'sPG_CATCH) cleanup blocks from firing on the same connection.
Patch Evolution
| Version | Key Change |
|---|---|
| V1 | Dedicated wrapper functions (libpqsrv_connect_with_notice_receiver()) — rejected as ad-hoc |
| V2 | Two-phase API introduced |
| V3 | Style cleanup: removed unnecessary local conn variables in _start functions |
| V4 | Removed redundant NULL checks before PQsetNoticeReceiver() (libpq handles NULL internally) |
Outcome
Committed on 2026-05-22 by Fujii Masao. The two-phase API follows libpq's own design philosophy (PQconnectStart/PQconnectPoll) and provides a general extension point for any per-connection setup needed between connection initiation and completion.