public inbox for [email protected]  
help / color / mirror / Atom feed
From: Roman Khapov <[email protected]>
To: Andrey Borodin <[email protected]>
To: Jim Jones <[email protected]>
Cc: Kirill Reshke <[email protected]>
Cc: Daniel Gustafsson <[email protected]>
Cc: [email protected]
Subject: Re: Additional message in pg_terminate_backend
Date: Tue, 3 Feb 2026 17:28:50 +0500
Message-ID: <[email protected]> (raw)
In-Reply-To: <[email protected]>
References: <[email protected]>
	<[email protected]>
	<[email protected]>
	<CALdSSPhU526xXqjsb=BPO689+qFJQDeimWrhOv=ehzveQsZJgw@mail.gmail.com>
	<[email protected]>
	<[email protected]>
	<[email protected]>
	<[email protected]>

Hi again Jim, Andrew!

Thanks for another round on review, updated the patch according to comments.

Also, fix `make check` by updating pg_proc.data with new functions,
similar to uuid7 way: defining _msg versions of the functions

--
Best regards,
Roman Khapov




> On 3 Feb 2026, at 13:26, Andrey Borodin <[email protected]> wrote:
> 
> 
> 
>> On 3 Feb 2026, at 12:52, Roman Khapov <[email protected]> wrote:
>> 
>> <v4-0001-message-in-pg_terminate_backend-and-pg_cancel_bac.patch>
> 
> Some notes on this version:
> 
> 1. Did you mean BackendMsgShmemSize()?
>    size = add_size(size, BackendStatusShmemSize());
> 
> 2. In docs: 
> 
> <function>pg_cancel_backend</function> ( <parameter>pid</parameter> <type>integer</type>, <parameter>message</parameter> <type>test</type> <literal>DEFAULT</literal> <literal>''</literal> )
> 
> Did you mean <type>text</type>?
> 
> 3. Windows build failed [0]
> 
> 4. In src/include/utils/misc/backend_msg.c identification is backend_msg.h
> 
> 
> Best regards, Andrey Borodin.
> 
> [0] https://github.com/x4m/postgres_g/runs/62314358734




Attachments:

  [application/octet-stream] v5-0001-message-in-pg_terminate_backend-and-pg_cancel_bac.patch (19.8K, 2-v5-0001-message-in-pg_terminate_backend-and-pg_cancel_bac.patch)
  download | inline diff:
From 67e0d1ca030c9ba24055c05f739eab70e6c296e4 Mon Sep 17 00:00:00 2001
From: roman khapov <[email protected]>
Date: Tue, 3 Feb 2026 10:19:39 +0000
Subject: [PATCH v5] message in pg_terminate_backend and pg_cancel_backend

Sometimes it is useful to terminate some backend
process with additional message from admin.

This patch introduces a new argument, message to
pg_terminate_backend and pg_cancel_backend.
The message, that will be passed into
FATAL/ERROR packet when terminating/canceling backend.

To do that, the patch introduces new module: BackendMsg - shared memory
region that holds pairs of (message, pid) which are checked in ProcessInterrupts()

Ex. of usage:
postgres=# select pg_terminate_backend(pg_backend_pid(), 0, 'Some message');
FATAL:  terminating connection due to administrator command: Some message

Author: Daniel Gustafsson <[email protected]>
Author: Roman Khapov <[email protected]>
Reviewed-by: Kirill Reshke <[email protected]>
Reviewed-by: Jim Jones <[email protected]>
Reviewed-by: Andrey Borodin <[email protected]>
---
 doc/src/sgml/func/func-admin.sgml             |  14 +-
 src/backend/storage/ipc/ipci.c                |   3 +
 src/backend/storage/ipc/signalfuncs.c         |  90 ++++++++--
 src/backend/tcop/postgres.c                   |  32 +++-
 src/backend/utils/init/postinit.c             |   2 +
 src/backend/utils/misc/Makefile               |   3 +-
 src/backend/utils/misc/backend_msg.c          | 157 ++++++++++++++++++
 src/backend/utils/misc/meson.build            |   1 +
 src/include/catalog/pg_proc.dat               |   7 +
 src/include/utils/backend_msg.h               |  28 ++++
 src/test/modules/test_misc/meson.build        |   1 +
 .../modules/test_misc/t/011_backend_msg.pl    |  42 +++++
 12 files changed, 362 insertions(+), 18 deletions(-)
 create mode 100644 src/backend/utils/misc/backend_msg.c
 create mode 100644 src/include/utils/backend_msg.h
 create mode 100644 src/test/modules/test_misc/t/011_backend_msg.pl

diff --git a/doc/src/sgml/func/func-admin.sgml b/doc/src/sgml/func/func-admin.sgml
index 3ac81905d1f..f0ab05fe774 100644
--- a/doc/src/sgml/func/func-admin.sgml
+++ b/doc/src/sgml/func/func-admin.sgml
@@ -147,7 +147,7 @@
         <indexterm>
          <primary>pg_cancel_backend</primary>
         </indexterm>
-        <function>pg_cancel_backend</function> ( <parameter>pid</parameter> <type>integer</type> )
+        <function>pg_cancel_backend</function> ( <parameter>pid</parameter> <type>integer</type>, <parameter>message</parameter> <type>text</type> <literal>DEFAULT</literal> <literal>''</literal> )
         <returnvalue>boolean</returnvalue>
        </para>
        <para>
@@ -160,6 +160,11 @@
         <literal>pg_signal_autovacuum_worker</literal> are permitted to
         cancel autovacuum worker processes, which are otherwise considered
         superuser backends.
+        If <parameter>message</parameter> is specified and non-empty, this
+        string will be passed as additional message in ERROR text for
+        canceled backend. Please note: if multiple backends
+        simultaneously terminate or cancel the same target, only one of those
+        messages will be delivered.
        </para></entry>
       </row>
 
@@ -225,7 +230,7 @@
         <indexterm>
          <primary>pg_terminate_backend</primary>
         </indexterm>
-        <function>pg_terminate_backend</function> ( <parameter>pid</parameter> <type>integer</type>, <parameter>timeout</parameter> <type>bigint</type> <literal>DEFAULT</literal> <literal>0</literal> )
+        <function>pg_terminate_backend</function> ( <parameter>pid</parameter> <type>integer</type>, <parameter>timeout</parameter> <type>bigint</type> <literal>DEFAULT</literal> <literal>0</literal>, <parameter>message</parameter> <type>text</type> <literal>DEFAULT</literal> <literal>''</literal>)
         <returnvalue>boolean</returnvalue>
        </para>
        <para>
@@ -249,6 +254,11 @@
         the process is terminated, the function
         returns <literal>true</literal>.  On timeout, a warning is emitted and
         <literal>false</literal> is returned.
+        If <parameter>message</parameter> is specified and non-empty, this
+        string will be passed as additional message in FATAL text for
+        terminated backend. Please note: if multiple backends
+        simultaneously terminate or cancel the same target, only one of those
+        messages will be delivered.
        </para></entry>
       </row>
      </tbody>
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index 1f7e933d500..ee8765c66c3 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -52,6 +52,7 @@
 #include "storage/sinvaladt.h"
 #include "utils/guc.h"
 #include "utils/injection_point.h"
+#include "utils/backend_msg.h"
 
 /* GUCs */
 int			shared_memory_type = DEFAULT_SHARED_MEMORY_TYPE;
@@ -140,6 +141,7 @@ CalculateShmemSize(void)
 	size = add_size(size, SlotSyncShmemSize());
 	size = add_size(size, AioShmemSize());
 	size = add_size(size, WaitLSNShmemSize());
+	size = add_size(size, BackendMsgShmemSize());
 	size = add_size(size, LogicalDecodingCtlShmemSize());
 
 	/* include additional requested shmem from preload libraries */
@@ -327,6 +329,7 @@ CreateOrAttachShmemStructs(void)
 	InjectionPointShmemInit();
 	AioShmemInit();
 	WaitLSNShmemInit();
+	BackendMsgShmemInit();
 	LogicalDecodingCtlShmemInit();
 }
 
diff --git a/src/backend/storage/ipc/signalfuncs.c b/src/backend/storage/ipc/signalfuncs.c
index 6f7759cd720..32cb06f8496 100644
--- a/src/backend/storage/ipc/signalfuncs.c
+++ b/src/backend/storage/ipc/signalfuncs.c
@@ -25,6 +25,8 @@
 #include "storage/procarray.h"
 #include "utils/acl.h"
 #include "utils/fmgrprotos.h"
+#include "utils/builtins.h"
+#include "utils/backend_msg.h"
 
 
 /*
@@ -48,7 +50,7 @@
 #define SIGNAL_BACKEND_NOSUPERUSER 3
 #define SIGNAL_BACKEND_NOAUTOVAC 4
 static int
-pg_signal_backend(int pid, int sig)
+pg_signal_backend(int pid, int sig, const char *msg)
 {
 	PGPROC	   *proc = BackendPidGetProc(pid);
 
@@ -111,6 +113,15 @@ pg_signal_backend(int pid, int sig)
 	 * too unlikely to worry about.
 	 */
 
+	if (msg != NULL && msg[0] != '\0')
+	{
+		int		r = BackendMsgSet(pid, msg);
+
+		if (r != -1 && r != strlen(msg))
+			ereport(NOTICE,
+					(errmsg("message is too long, truncated to %d bytes", r)));
+	}
+
 	/* If we have setsid(), signal the backend's whole process group */
 #ifdef HAVE_SETSID
 	if (kill(-pid, sig))
@@ -132,10 +143,10 @@ pg_signal_backend(int pid, int sig)
  *
  * Note that only superusers can signal superuser-owned processes.
  */
-Datum
-pg_cancel_backend(PG_FUNCTION_ARGS)
+static Datum
+pg_cancel_backend_internal(pid_t pid, const char *msg)
 {
-	int			r = pg_signal_backend(PG_GETARG_INT32(0), SIGINT);
+	int			r = pg_signal_backend(pid, SIGINT, msg);
 
 	if (r == SIGNAL_BACKEND_NOSUPERUSER)
 		ereport(ERROR,
@@ -161,6 +172,34 @@ pg_cancel_backend(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(r == SIGNAL_BACKEND_SUCCESS);
 }
 
+Datum pg_cancel_backend(PG_FUNCTION_ARGS)
+{
+	int		pid;
+
+	pid = PG_GETARG_INT32(0);
+
+	return pg_cancel_backend_internal(pid, NULL);
+}
+
+Datum pg_cancel_backend_msg(PG_FUNCTION_ARGS)
+{
+	int		pid;
+	char	*msg;
+	Datum	result;
+
+	pid = PG_GETARG_INT32(0);
+	msg = text_to_cstring(PG_GETARG_TEXT_PP(1));
+	if (msg == NULL) {
+		PG_RETURN_BOOL(false);
+	}
+
+	result = pg_cancel_backend_internal(pid, msg);
+
+	pfree(msg);
+
+	return result;
+}
+
 /*
  * Wait until there is no backend process with the given PID and return true.
  * On timeout, a warning is emitted and false is returned.
@@ -233,22 +272,17 @@ pg_wait_until_termination(int pid, int64 timeout)
  *
  * Note that only superusers can signal superuser-owned processes.
  */
-Datum
-pg_terminate_backend(PG_FUNCTION_ARGS)
+static Datum
+pg_terminate_backend_internal(int pid, int timeout, const char *msg)
 {
-	int			pid;
 	int			r;
-	int			timeout;		/* milliseconds */
-
-	pid = PG_GETARG_INT32(0);
-	timeout = PG_GETARG_INT64(1);
 
 	if (timeout < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("\"timeout\" must not be negative")));
 
-	r = pg_signal_backend(pid, SIGTERM);
+	r = pg_signal_backend(pid, SIGTERM, msg);
 
 	if (r == SIGNAL_BACKEND_NOSUPERUSER)
 		ereport(ERROR,
@@ -278,6 +312,38 @@ pg_terminate_backend(PG_FUNCTION_ARGS)
 		PG_RETURN_BOOL(r == SIGNAL_BACKEND_SUCCESS);
 }
 
+Datum pg_terminate_backend(PG_FUNCTION_ARGS)
+{
+	int		pid;
+	int		timeout_ms;
+
+	pid = PG_GETARG_INT32(0);
+	timeout_ms = PG_GETARG_INT64(1);
+
+	return pg_terminate_backend_internal(pid, timeout_ms, NULL);
+}
+
+Datum pg_terminate_backend_msg(PG_FUNCTION_ARGS)
+{
+	int		pid;
+	int		timeout_ms;
+	char	*msg;
+	Datum	result;
+
+	pid = PG_GETARG_INT32(0);
+	timeout_ms = PG_GETARG_INT64(1);
+	msg = text_to_cstring(PG_GETARG_TEXT_PP(2));
+	if (msg == NULL) {
+		PG_RETURN_BOOL(false);
+	}
+
+	result = pg_terminate_backend_internal(pid, timeout_ms, msg);
+
+	pfree(msg);
+
+	return result;
+}
+
 /*
  * Signal to reload the database configuration
  *
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index b4a8d2f3a1c..3c6d285a4dc 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -81,6 +81,7 @@
 #include "utils/timeout.h"
 #include "utils/timestamp.h"
 #include "utils/varlena.h"
+#include "utils/backend_msg.h"
 
 /* ----------------
  *		global variables
@@ -3356,9 +3357,22 @@ ProcessInterrupts(void)
 			proc_exit(0);
 		}
 		else
+		{
+			if (BackendMsgIsSet())
+			{
+				char msg[BACKEND_MSG_MAX_LEN];
+
+				BackendMsgGet(msg, sizeof(msg));
+
+				ereport(FATAL,
+						(errcode(ERRCODE_ADMIN_SHUTDOWN),
+						errmsg("terminating connection due to administrator command: %s", msg)));
+			}
+
 			ereport(FATAL,
 					(errcode(ERRCODE_ADMIN_SHUTDOWN),
 					 errmsg("terminating connection due to administrator command")));
+		}
 	}
 
 	if (CheckClientConnectionPending)
@@ -3466,9 +3480,21 @@ ProcessInterrupts(void)
 		if (!DoingCommandRead)
 		{
 			LockErrorCleanup();
-			ereport(ERROR,
-					(errcode(ERRCODE_QUERY_CANCELED),
-					 errmsg("canceling statement due to user request")));
+
+			if (BackendMsgIsSet())
+			{
+				char msg[BACKEND_MSG_MAX_LEN];
+
+				BackendMsgGet(msg, sizeof(msg));
+
+				ereport(ERROR,
+						(errcode(ERRCODE_QUERY_CANCELED),
+						 errmsg("canceling statement due to user request: %s", msg)));
+			}
+			else
+				ereport(ERROR,
+						(errcode(ERRCODE_QUERY_CANCELED),
+						 errmsg("canceling statement due to user request")));
 		}
 	}
 
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 3f401faf3de..debf6da4a7b 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -69,6 +69,7 @@
 #include "utils/snapmgr.h"
 #include "utils/syscache.h"
 #include "utils/timeout.h"
+#include "utils/backend_msg.h"
 
 static HeapTuple GetDatabaseTuple(const char *dbname);
 static HeapTuple GetDatabaseTupleByOid(Oid dboid);
@@ -902,6 +903,7 @@ InitPostgres(const char *in_dbname, Oid dboid,
 			InitializeSystemUser(MyClientConnectionInfo.authn_id,
 								 hba_authname(MyClientConnectionInfo.auth_method));
 		am_superuser = superuser();
+		BackendMsgInit(MyProcNumber);
 	}
 
 	/* Report any SSL/GSS details for the session. */
diff --git a/src/backend/utils/misc/Makefile b/src/backend/utils/misc/Makefile
index f142d17178b..5494994669f 100644
--- a/src/backend/utils/misc/Makefile
+++ b/src/backend/utils/misc/Makefile
@@ -32,7 +32,8 @@ OBJS = \
 	stack_depth.o \
 	superuser.o \
 	timeout.o \
-	tzparser.o
+	tzparser.o \
+	backend_msg.o
 
 # This location might depend on the installation directories. Therefore
 # we can't substitute it into pg_config.h.
diff --git a/src/backend/utils/misc/backend_msg.c b/src/backend/utils/misc/backend_msg.c
new file mode 100644
index 00000000000..34d44069056
--- /dev/null
+++ b/src/backend/utils/misc/backend_msg.c
@@ -0,0 +1,157 @@
+/*--------------------------------------------------------------------
+ * backend_msg.c
+ *
+ * Utility to pass additional message to backend processes.
+ * Ex: cancel or terminate messages
+ *
+ * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/utils/misc/backend_msg.c
+ *
+ *--------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "miscadmin.h"
+#include "mb/pg_wchar.h"
+#include "storage/shmem.h"
+#include "storage/spin.h"
+#include "storage/ipc.h"
+#include "utils/backend_msg.h"
+
+typedef struct {
+	pid_t pid;
+	slock_t lock;
+	char msg[BACKEND_MSG_MAX_LEN];
+} BackendMsgSlot;
+
+
+static BackendMsgSlot *BackendMsgSlots;
+static BackendMsgSlot *MyBackendMsgSlot;
+
+static void
+backend_msg_slot_clean(int code, Datum arg)
+{
+	(void) code;
+	(void) arg;
+
+	Assert(MyBackendMsgSlot != NULL);
+
+	SpinLockAcquire(&MyBackendMsgSlot->lock);
+
+	MyBackendMsgSlot->msg[0] = '\0';
+	MyBackendMsgSlot->pid = 0;
+
+	SpinLockRelease(&MyBackendMsgSlot->lock);
+
+	MyBackendMsgSlot = NULL;
+}
+
+void BackendMsgShmemInit(void)
+{
+	Size	size;
+	bool	found;
+
+	size = BackendMsgShmemSize();
+	BackendMsgSlots = ShmemInitStruct("BackendMsgSlots", size, &found);
+
+	if (found)
+		return;
+
+	memset(BackendMsgSlots, 0, size);
+
+	for (int i = 0; i < MaxBackends; ++i)
+		SpinLockInit(&BackendMsgSlots[i].lock);
+}
+
+Size
+BackendMsgShmemSize(void)
+{
+	return mul_size(MaxBackends, sizeof(BackendMsgSlot));
+}
+
+void BackendMsgInit(int id)
+{
+	BackendMsgSlot		*slot;
+
+	slot = &BackendMsgSlots[id];
+
+	slot->msg[0] = '\0';
+	slot->pid = MyProcPid;
+
+	MyBackendMsgSlot = slot;
+
+	on_shmem_exit(backend_msg_slot_clean, Int32GetDatum(0) /* not used */);
+}
+
+int BackendMsgSet(pid_t pid, const char *msg)
+{
+	BackendMsgSlot		*slot;
+	int					len;
+
+	if (msg == NULL || msg[0] == '\0')
+		return 0;
+
+	for (int i = 0; i < MaxBackends; ++i)
+	{
+		slot = &BackendMsgSlots[i];
+
+		if (slot->pid == 0 || slot->pid != pid)
+			continue;
+
+		SpinLockAcquire(&slot->lock);
+
+		if (slot->pid != pid)
+		{
+			SpinLockRelease(&slot->lock);
+			break;
+		}
+
+		len = pg_mbcliplen(msg, strlen(msg), sizeof(slot->msg) - 1);
+		memcpy(slot->msg, msg, len);
+		slot->msg[len] = '\0';
+
+		SpinLockRelease(&slot->lock);
+
+		return len;
+	}
+
+	ereport(LOG,
+			(errmsg("can't set message for missing backend %ld, requested by %ld",
+				(long) pid, (long) MyProcPid)));
+
+	return -1;
+}
+
+int BackendMsgGet(char *buf, int max_len)
+{
+	int		len;
+
+	if (MyBackendMsgSlot == NULL)
+		return 0;
+
+	SpinLockAcquire(&MyBackendMsgSlot->lock);
+
+	len = strlcpy(buf, MyBackendMsgSlot->msg, max_len);
+	memset(MyBackendMsgSlot->msg, '\0', sizeof(MyBackendMsgSlot->msg));
+
+	SpinLockRelease(&MyBackendMsgSlot->lock);
+
+	return len;
+}
+
+bool BackendMsgIsSet(void)
+{
+	bool result = false;
+
+	if (MyBackendMsgSlot == NULL)
+		return false;
+
+	SpinLockAcquire(&MyBackendMsgSlot->lock);
+	result = MyBackendMsgSlot->msg[0] != '\0';
+	SpinLockRelease(&MyBackendMsgSlot->lock);
+
+	return result;
+}
diff --git a/src/backend/utils/misc/meson.build b/src/backend/utils/misc/meson.build
index 232e74d0af9..831bf6c6bab 100644
--- a/src/backend/utils/misc/meson.build
+++ b/src/backend/utils/misc/meson.build
@@ -1,6 +1,7 @@
 # Copyright (c) 2022-2026, PostgreSQL Global Development Group
 
 backend_sources += files(
+  'backend_msg.c',
   'conffiles.c',
   'guc.c',
   'guc_funcs.c',
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 5e5e33f64fc..36df85318f4 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6725,10 +6725,17 @@
 { oid => '2171', descr => 'cancel a server process\' current query',
   proname => 'pg_cancel_backend', provolatile => 'v', prorettype => 'bool',
   proargtypes => 'int4', prosrc => 'pg_cancel_backend' },
+{ oid => '8223', descr => 'cancel a server process\' current query',
+  proname => 'pg_cancel_backend', provolatile => 'v', prorettype => 'bool',
+  proargtypes => 'int4 text', prosrc => 'pg_cancel_backend_msg' },
 { oid => '2096', descr => 'terminate a server process',
   proname => 'pg_terminate_backend', provolatile => 'v', prorettype => 'bool',
   proargtypes => 'int4 int8', proargnames => '{pid,timeout}',
   prosrc => 'pg_terminate_backend' },
+{ oid => '8222', descr => 'terminate a server process',
+  proname => 'pg_terminate_backend', provolatile => 'v', prorettype => 'bool',
+  proargtypes => 'int4 int8 text', proargnames => '{pid,timeout,message}',
+  prosrc => 'pg_terminate_backend_msg' },
 { oid => '2172', descr => 'prepare for taking an online backup',
   proname => 'pg_backup_start', provolatile => 'v', proparallel => 'r',
   prorettype => 'pg_lsn', proargtypes => 'text bool',
diff --git a/src/include/utils/backend_msg.h b/src/include/utils/backend_msg.h
new file mode 100644
index 00000000000..7e53c59845f
--- /dev/null
+++ b/src/include/utils/backend_msg.h
@@ -0,0 +1,28 @@
+/*--------------------------------------------------------------------
+ * backend_msg.h
+ *
+ * Utility to pass additional message to backend processes.
+ * Ex: cancel or terminate messages
+ *
+ * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/utils/backend_msg.h
+ *
+ *--------------------------------------------------------------------
+ */
+
+#ifndef BACKEND_MSG_H
+#define BACKEND_MSG_H
+
+#define BACKEND_MSG_MAX_LEN 128
+
+extern void BackendMsgShmemInit(void);
+extern Size BackendMsgShmemSize(void);
+extern void BackendMsgInit(int id);
+extern int BackendMsgSet(pid_t pid, const char *msg);
+extern int BackendMsgGet(char *buf, int max_len);
+extern bool BackendMsgIsSet(void);
+
+
+#endif /* BACKEND_MSG_H */
diff --git a/src/test/modules/test_misc/meson.build b/src/test/modules/test_misc/meson.build
index 6e8db1621a7..674675b7ce1 100644
--- a/src/test/modules/test_misc/meson.build
+++ b/src/test/modules/test_misc/meson.build
@@ -19,6 +19,7 @@ tests += {
       't/008_replslot_single_user.pl',
       't/009_log_temp_files.pl',
       't/010_index_concurrently_upsert.pl',
+      't/011_backend_msg.pl',
     ],
     # The injection points are cluster-wide, so disable installcheck
     'runningcheck': false,
diff --git a/src/test/modules/test_misc/t/011_backend_msg.pl b/src/test/modules/test_misc/t/011_backend_msg.pl
new file mode 100644
index 00000000000..94448821a67
--- /dev/null
+++ b/src/test/modules/test_misc/t/011_backend_msg.pl
@@ -0,0 +1,42 @@
+# Copyright (c) 2025, PostgreSQL Global Development Group
+
+# Check that messages are passed to backends by
+# pg_terminate_backend, pg_cancel_backend
+
+use strict;
+use warnings FATAL => 'all';
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+my $node = PostgreSQL::Test::Cluster->new('primary');
+$node->init();
+$node->start;
+
+my ($stdout, $stderr);
+$node->psql('postgres',
+	q[select pg_terminate_backend(pg_backend_pid(), 0, 'Have you seen my coffee cup?');],
+	stdout => \$stdout, stderr => \$stderr);
+like($stderr, qr/Have you seen my coffee cup\?/, "expected message to be passed in pg_terminate_backend");
+
+$stdout = '';
+$stderr = '';
+$node->psql('postgres',
+	q[select pg_cancel_backend(pg_backend_pid(), 'You have to wear some ridiculous tie');],
+	stdout => \$stdout, stderr => \$stderr);
+like($stderr, qr/You have to wear some ridiculous tie/, "expected message to be passed in pg_cancel_backend");
+
+$stdout = '';
+$stderr = '';
+my $longstr = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+my $truncated = substr($longstr, 0, 127);
+$node->psql('postgres',
+	qq[select pg_terminate_backend(pg_backend_pid(), 0, '$longstr');],
+	stdout => \$stdout, stderr => \$stderr);
+like($stderr, qr/NOTICE:  message is too long, truncated to 127 bytes/, "NOTICE message should be created");
+like($stderr, qr/\Q$truncated\E/, "expected truncated message (127 chars) to be passed");
+unlike($stderr, qr/\Q$longstr\E/, "full message must not be passed");
+
+$node->stop;
+
+done_testing();
-- 
2.43.0



view thread (10+ messages)  latest in thread

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: [email protected]
  Cc: [email protected], [email protected], [email protected], [email protected], [email protected], [email protected]
  Subject: Re: Additional message in pg_terminate_backend
  In-Reply-To: <[email protected]>

* 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