public inbox for pgsql-hackers@postgresql.org  
help / color / mirror / Atom feed
From: Chao Li <li.evan.chao@gmail.com>
To: PostgreSQL-development <pgsql-hackers@postgresql.org>
Cc: Fujii Masao <masao.fujii@gmail.com>
Cc: vignesh C <vignesh21@gmail.com>
Subject: Set notice receiver before libpq connection startup
Date: Wed, 20 May 2026 15:21:08 +0800
Message-ID: <A2B8B7DE-C119-492F-A9FA-14CF86849777@gmail.com> (raw)

Hi,

While testing “Log remote NOTICE, WARNING, and similar messages using ereport()”, I noticed that libpqsrv_notice_receiver is only installed after libpqsrv_connect() finishes. As a result, NOTICE messages generated during connection establishment are missed by ereport() and are still printed to stderr.

To reproduce the issue, I created a separate database called remotedb and defined a login trigger that emits a NOTICE message:
```
CREATE DATABASE remotedb;

\c remotedb

CREATE OR REPLACE FUNCTION repro_login_notice()
RETURNS event_trigger
LANGUAGE plpgsql AS $$
BEGIN
  RAISE NOTICE 'startup notice from remotedb login trigger';
END;
$$;

CREATE EVENT TRIGGER repro_login_notice_trg
ON login
EXECUTE FUNCTION repro_login_notice();

ALTER EVENT TRIGGER repro_login_notice_trg ENABLE ALWAYS;
```

Then, from another database:
```
evantest=# create extension dblink;
CREATE EXTENSION
evantest=# SELECT dblink_connect('host=127.0.0.1 port=5432 dbname=remotedb user=chaol sslmode=disable gssencmode=disable');
 dblink_connect
----------------
 OK
(1 row)
```

In the system log, the NOTICE message is printed directly:
```
2026-05-20 13:02:19.350 CST [24909] STATEMENT:  SELECT dblink_connect('host=127.0.0.1 port=5432 dbname=remotedb user=chaol sslmode=disable gssencmode=disable');
NOTICE:  startup notice from remotedb login trigger
```

To fix that, I think we should install libpqsrv_notice_receiver before libpqsrv_connect_internal(). In the attached patch, I added two helpers: libpqsrv_connect_with_notice_receiver() and libpqsrv_connect_params_with_notice_receiver().

With the fix, the NOTICE message now looks like this:
```
2026-05-20 14:44:49.296 CST [45567] LOG:  received message via remote connection: NOTICE:  startup notice from remotedb login trigger
2026-05-20 14:44:49.296 CST [45567] STATEMENT:  SELECT dblink_connect('host=127.0.0.1 port=5432 dbname=remotedb user=chaol sslmode=disable gssencmode=disable');
```

Please see the attached patch for details.

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/






Attachments:

  [application/octet-stream] v1-0001-Set-notice-receiver-before-libpq-connection-start.patch (7.6K, 2-v1-0001-Set-notice-receiver-before-libpq-connection-start.patch)
  download | inline diff:
From db52f5949884e57769b7ba7fc56be64c47ef1fa1 Mon Sep 17 00:00:00 2001
From: "Chao Li (Evan)" <lic@highgo.com>
Date: Wed, 20 May 2026 14:57:25 +0800
Subject: [PATCH v1] Set notice receiver before libpq connection startup

Some callers of libpqsrv_connect() and libpqsrv_connect_params()
install libpqsrv_notice_receiver after the connection has been
established. However, notices may also be received while
libpqsrv_connect_internal() is still processing the asynchronous
connection startup.

Add variants of these helpers that install a notice receiver immediately
after PQconnectStart() or PQconnectStartParams(), before entering
libpqsrv_connect_internal(). Use them in dblink, postgres_fdw, and
libpqwalreceiver, so notices emitted during connection startup are
handled in the same way as notices received after the connection is
established.

Author: Chao Li <lic@highgo.com>
Reviewed-by:
Discussion: https://postgr.es/m/
---
 contrib/dblink/dblink.c                       | 15 ++++---
 contrib/postgres_fdw/connection.c             | 11 +++--
 .../libpqwalreceiver/libpqwalreceiver.c       | 11 +++--
 src/include/libpq/libpq-be-fe-helpers.h       | 42 ++++++++++++++-----
 4 files changed, 49 insertions(+), 30 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index d843eee7e97..2093aef990f 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -222,7 +222,10 @@ dblink_get_conn(char *conname_or_str,
 			dblink_we_get_conn = WaitEventExtensionNew("DblinkGetConnect");
 
 		/* OK to make connection */
-		conn = libpqsrv_connect(connstr, dblink_we_get_conn);
+		conn = libpqsrv_connect_with_notice_receiver(connstr,
+													 dblink_we_get_conn,
+													 libpqsrv_notice_receiver,
+													 "received message via remote connection");
 
 		if (PQstatus(conn) == CONNECTION_BAD)
 		{
@@ -235,9 +238,6 @@ dblink_get_conn(char *conname_or_str,
 					 errdetail_internal("%s", msg)));
 		}
 
-		PQsetNoticeReceiver(conn, libpqsrv_notice_receiver,
-							"received message via remote connection");
-
 		dblink_security_check(conn, NULL, connstr);
 		if (PQclientEncoding(conn) != GetDatabaseEncoding())
 			PQsetClientEncoding(conn, GetDatabaseEncodingName());
@@ -321,7 +321,9 @@ dblink_connect(PG_FUNCTION_ARGS)
 	}
 
 	/* OK to make connection */
-	conn = libpqsrv_connect(connstr, dblink_we_connect);
+	conn = libpqsrv_connect_with_notice_receiver(connstr, dblink_we_connect,
+												 libpqsrv_notice_receiver,
+												 "received message via remote connection");
 
 	if (PQstatus(conn) == CONNECTION_BAD)
 	{
@@ -336,9 +338,6 @@ dblink_connect(PG_FUNCTION_ARGS)
 				 errdetail_internal("%s", msg)));
 	}
 
-	PQsetNoticeReceiver(conn, libpqsrv_notice_receiver,
-						"received message via remote connection");
-
 	/* check password actually used if not superuser */
 	dblink_security_check(conn, connname, connstr);
 
diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c
index 3d2a8d0519d..0278f4a7cea 100644
--- a/contrib/postgres_fdw/connection.c
+++ b/contrib/postgres_fdw/connection.c
@@ -646,9 +646,11 @@ connect_pg_server(ForeignServer *server, UserMapping *user)
 			pgfdw_we_connect = WaitEventExtensionNew("PostgresFdwConnect");
 
 		/* OK to make connection */
-		conn = libpqsrv_connect_params(keywords, values,
-									   false,	/* expand_dbname */
-									   pgfdw_we_connect);
+		conn = libpqsrv_connect_params_with_notice_receiver(keywords, values,
+															false,	/* expand_dbname */
+															pgfdw_we_connect,
+															libpqsrv_notice_receiver,
+															"received message via remote connection");
 
 		if (!conn || PQstatus(conn) != CONNECTION_OK)
 			ereport(ERROR,
@@ -657,9 +659,6 @@ connect_pg_server(ForeignServer *server, UserMapping *user)
 							server->servername),
 					 errdetail_internal("%s", pchomp(PQerrorMessage(conn)))));
 
-		PQsetNoticeReceiver(conn, libpqsrv_notice_receiver,
-							"received message via remote connection");
-
 		/* Perform post-connection security checks. */
 		pgfdw_security_check(keywords, values, user, conn);
 
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index 9f04c9ed25d..cc5f77d53f7 100644
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
@@ -223,9 +223,11 @@ libpqrcv_connect(const char *conninfo, bool replication, bool logical,
 
 	conn = palloc0_object(WalReceiverConn);
 	conn->streamConn =
-		libpqsrv_connect_params(keys, vals,
-								 /* expand_dbname = */ true,
-								WAIT_EVENT_LIBPQWALRECEIVER_CONNECT);
+		libpqsrv_connect_params_with_notice_receiver(keys, vals,
+													  /* expand_dbname = */ true,
+													 WAIT_EVENT_LIBPQWALRECEIVER_CONNECT,
+													 libpqsrv_notice_receiver,
+													 "received message via replication");
 
 	if (options_val != NULL)
 		pfree(options_val);
@@ -245,9 +247,6 @@ libpqrcv_connect(const char *conninfo, bool replication, bool logical,
 				 errhint("Target server's authentication method must be changed, or set password_required=false in the subscription parameters.")));
 	}
 
-	PQsetNoticeReceiver(conn->streamConn, libpqsrv_notice_receiver,
-						"received message via replication");
-
 	/*
 	 * Set always-secure search path for the cases where the connection is
 	 * used to run SQL queries, so malicious users can't get control.
diff --git a/src/include/libpq/libpq-be-fe-helpers.h b/src/include/libpq/libpq-be-fe-helpers.h
index 85d8b63f019..0571bb1fe50 100644
--- a/src/include/libpq/libpq-be-fe-helpers.h
+++ b/src/include/libpq/libpq-be-fe-helpers.h
@@ -43,6 +43,23 @@ static inline void libpqsrv_connect_internal(PGconn *conn, uint32 wait_event_inf
 static inline PGresult *libpqsrv_get_result_last(PGconn *conn, uint32 wait_event_info);
 static inline PGresult *libpqsrv_get_result(PGconn *conn, uint32 wait_event_info);
 
+static inline PGconn *
+libpqsrv_connect_with_notice_receiver(const char *conninfo,
+									  uint32 wait_event_info,
+									  PQnoticeReceiver proc, void *arg)
+{
+	PGconn	   *conn = NULL;
+
+	libpqsrv_connect_prepare();
+
+	conn = PQconnectStart(conninfo);
+	if (conn != NULL && proc != NULL)
+		PQsetNoticeReceiver(conn, proc, arg);
+
+	libpqsrv_connect_internal(conn, wait_event_info);
+
+	return conn;
+}
 
 /*
  * PQconnectdb() wrapper that reserves a file descriptor and processes
@@ -54,12 +71,24 @@ static inline PGresult *libpqsrv_get_result(PGconn *conn, uint32 wait_event_info
  */
 static inline PGconn *
 libpqsrv_connect(const char *conninfo, uint32 wait_event_info)
+{
+	return libpqsrv_connect_with_notice_receiver(conninfo, wait_event_info, NULL, NULL);
+}
+
+static inline PGconn *
+libpqsrv_connect_params_with_notice_receiver(const char *const *keywords,
+											 const char *const *values,
+											 int expand_dbname,
+											 uint32 wait_event_info,
+											 PQnoticeReceiver proc, void *arg)
 {
 	PGconn	   *conn = NULL;
 
 	libpqsrv_connect_prepare();
 
-	conn = PQconnectStart(conninfo);
+	conn = PQconnectStartParams(keywords, values, expand_dbname);
+	if (conn != NULL && proc != NULL)
+		PQsetNoticeReceiver(conn, proc, arg);
 
 	libpqsrv_connect_internal(conn, wait_event_info);
 
@@ -76,15 +105,8 @@ libpqsrv_connect_params(const char *const *keywords,
 						int expand_dbname,
 						uint32 wait_event_info)
 {
-	PGconn	   *conn = NULL;
-
-	libpqsrv_connect_prepare();
-
-	conn = PQconnectStartParams(keywords, values, expand_dbname);
-
-	libpqsrv_connect_internal(conn, wait_event_info);
-
-	return conn;
+	return libpqsrv_connect_params_with_notice_receiver(keywords, values, expand_dbname,
+														wait_event_info, NULL, NULL);
 }
 
 /*
-- 
2.50.1 (Apple Git-155)



reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: pgsql-hackers@postgresql.org
  Cc: li.evan.chao@gmail.com, masao.fujii@gmail.com, vignesh21@gmail.com
  Subject: Re: Set notice receiver before libpq connection startup
  In-Reply-To: <A2B8B7DE-C119-492F-A9FA-14CF86849777@gmail.com>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox