Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vnBDu-003M9l-1o for pgsql-hackers@arkaria.postgresql.org; Tue, 03 Feb 2026 07:53:23 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vnBDt-003q8b-27 for pgsql-hackers@arkaria.postgresql.org; Tue, 03 Feb 2026 07:53:21 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vnBDs-003q8T-38 for pgsql-hackers@lists.postgresql.org; Tue, 03 Feb 2026 07:53:21 +0000 Received: from forwardcorp1d.mail.yandex.net ([2a02:6b8:c41:1300:1:45:d181:df01]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1vnBDp-00000000JkI-0eXT for pgsql-hackers@lists.postgresql.org; Tue, 03 Feb 2026 07:53:19 +0000 Received: from mail-nwsmtp-smtp-corp-main-80.iva.yp-c.yandex.net (mail-nwsmtp-smtp-corp-main-80.iva.yp-c.yandex.net [IPv6:2a02:6b8:c0c:1593:0:640:6beb:0]) by forwardcorp1d.mail.yandex.net (Yandex) with ESMTPS id E43D7818F2; Tue, 03 Feb 2026 10:53:08 +0300 (MSK) Received: from smtpclient.apple (unknown [2a02:6bf:803e:e00:30df:a89e:99a8:50fa]) by mail-nwsmtp-smtp-corp-main-80.iva.yp-c.yandex.net (smtpcorp/Yandex) with ESMTPSA id 7ri4vK0A5Gk0-CECIlPKM; Tue, 03 Feb 2026 10:53:08 +0300 X-Yandex-Fwd: 1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yandex-team.ru; s=default; t=1770105188; bh=RoV8TAr6V18VWb5FbVoq6RSOi86siFODQw2T/TGtXOg=; h=References:To:Cc:In-Reply-To:Date:From:Message-Id:Subject; b=wv6lA+L2yBVFlSMZNAJWzW9qPogw/GNTlQJ1mtOj4tG73ERjzpC82gfcoUIwzBRYH eQBLOYl8i6eAu0w3rhLJjWs7Lav72EQ4DS3jvx79DszRO+v3eHCjKoKHshNj+cQL7h BuC+PRyWKyiEeF2O+Lm0vJ+rGuSqk8BeZOo5DuYo= Authentication-Results: mail-nwsmtp-smtp-corp-main-80.iva.yp-c.yandex.net; dkim=pass header.i=@yandex-team.ru From: Roman Khapov Message-Id: Content-Type: multipart/mixed; boundary="Apple-Mail=_090BCC24-D0A3-49F3-9E83-9FA4411ED2D4" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3864.300.41.1.7\)) Subject: Re: Additional message in pg_terminate_backend Date: Tue, 3 Feb 2026 12:52:57 +0500 In-Reply-To: <7e8c913b-1bfb-41f1-b5db-c29e2af48daa@uni-muenster.de> Cc: Kirill Reshke , Daniel Gustafsson , pgsql-hackers@lists.postgresql.org To: Jim Jones References: <064E214D-D86F-4917-A0B6-67EAD6BCB24A@yandex-team.ru> <99f3524c-6aee-4fe2-8f3f-fcf0b67642c2@uni-muenster.de> <7e8c913b-1bfb-41f1-b5db-c29e2af48daa@uni-muenster.de> X-Mailer: Apple Mail (2.3864.300.41.1.7) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --Apple-Mail=_090BCC24-D0A3-49F3-9E83-9FA4411ED2D4 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii Hi Jim! Thanks for your review and rebase! > Since the message's size is limited to BACKEND_MSG_MAX_LEN, shouldn't > you use it to limit msg at pg_terminate_backend[_msg]()? Something like: > The message is truncated inside BackendMsgSet function, so I see a little point in truncating it at pg_terminate_backend.. Also, changing the stpncpy() to strlcpy() breaks the logic of returning result length of the message and NOTICE message about it, so I reverted this change. But this note make me think about adding test to truncation logic, so I added it in v4. -- Best regards, Roman Khapov --Apple-Mail=_090BCC24-D0A3-49F3-9E83-9FA4411ED2D4 Content-Disposition: attachment; filename=v4-0001-message-in-pg_terminate_backend-and-pg_cancel_bac.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v4-0001-message-in-pg_terminate_backend-and-pg_cancel_bac.patch" Content-Transfer-Encoding: quoted-printable =46rom=20c335e0c6b19982c9ea45b1979be4eeaa4ab3ece3=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20roman=20khapov=20=0ADate:=20= Tue,=203=20Feb=202026=2007:37:15=20+0000=0ASubject:=20[PATCH=20v4]=20= message=20in=20pg_terminate_backend=20and=20pg_cancel_backend=0A=0A= Sometimes=20it=20is=20useful=20to=20terminate=20some=20backend=0Aprocess=20= with=20additional=20message=20from=20admin.=0A=0AThis=20patch=20= introduces=20a=20new=20argument,=20message=20to=0Apg_terminate_backend=20= and=20pg_cancel_backend.=0AThe=20message,=20that=20will=20be=20passed=20= into=0AFATAL/ERROR=20packet=20when=20terminating/canceling=20backend.=0A=0A= To=20do=20that,=20the=20patch=20introduces=20new=20module:=20BackendMsg=20= -=20shared=20memory=0Aregion=20that=20holds=20pairs=20of=20(message,=20= pid)=20which=20are=20checked=20in=20ProcessInterrupts()=0A=0AEx.=20of=20= usage:=0Apostgres=3D#=20select=20pg_terminate_backend(pg_backend_pid(),=20= 0,=20'Some=20message');=0AFATAL:=20=20terminating=20connection=20due=20= to=20administrator=20command:=20Some=20message=0A=0AAuthor:=20Daniel=20= Gustafsson=20=0AAuthor:=20Roman=20Khapov=20= =0AReviewed-by:=20Kirill=20Reshke=20= =0AReviewed-by:=20Jim=20Jones=20= =0A---=0A=20doc/src/sgml/func/func-admin.sgml=20= =20=20=20=20=20=20=20=20=20=20=20=20|=20=2010=20+-=0A=20= src/backend/catalog/system_functions.sql=20=20=20=20=20=20|=20=20=207=20= +-=0A=20src/backend/storage/ipc/ipci.c=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20|=20=20=203=20+=0A=20src/backend/storage/ipc/signalfuncs.c=20= =20=20=20=20=20=20=20=20|=20=2054=20++++--=0A=20= src/backend/tcop/postgres.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20|=20=2032=20+++-=0A=20src/backend/utils/init/postinit.c=20=20=20= =20=20=20=20=20=20=20=20=20=20|=20=20=202=20+=0A=20= src/backend/utils/misc/Makefile=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20|=20=20=203=20+-=0A=20src/backend/utils/misc/backend_msg.c=20=20=20=20= =20=20=20=20=20=20|=20156=20++++++++++++++++++=0A=20= src/backend/utils/misc/meson.build=20=20=20=20=20=20=20=20=20=20=20=20|=20= =20=201=20+=0A=20src/include/utils/backend_msg.h=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20|=20=2028=20++++=0A=20= src/test/modules/test_misc/meson.build=20=20=20=20=20=20=20=20|=20=20=20= 1=20+=0A=20.../modules/test_misc/t/011_backend_msg.pl=20=20=20=20|=20=20= 42=20+++++=0A=2012=20files=20changed,=20320=20insertions(+),=2019=20= deletions(-)=0A=20create=20mode=20100644=20= src/backend/utils/misc/backend_msg.c=0A=20create=20mode=20100644=20= src/include/utils/backend_msg.h=0A=20create=20mode=20100644=20= src/test/modules/test_misc/t/011_backend_msg.pl=0A=0Adiff=20--git=20= a/doc/src/sgml/func/func-admin.sgml=20= b/doc/src/sgml/func/func-admin.sgml=0Aindex=203ac81905d1f..40bc0947f75=20= 100644=0A---=20a/doc/src/sgml/func/func-admin.sgml=0A+++=20= b/doc/src/sgml/func/func-admin.sgml=0A@@=20-147,7=20+147,7=20@@=0A=20=20=20= =20=20=20=20=20=20=0A=20=20=20=20=20=20=20=20=20=20= pg_cancel_backend=0A=20=20=20=20=20=20=20=20=20= =0A-=20=20=20=20=20=20=20=20= pg_cancel_backend=20(=20pid=20= integer=20)=0A+=20=20=20=20=20=20=20=20= pg_cancel_backend=20(=20pid=20= integer,=20message=20= test=20DEFAULT=20''=20= )=0A=20=20=20=20=20=20=20=20=20boolean=0A=20=20= =20=20=20=20=20=20=0A=20=20=20=20=20=20=20=20=0A@@=20-160,6=20= +160,9=20@@=0A=20=20=20=20=20=20=20=20=20= pg_signal_autovacuum_worker=20are=20permitted=20to=0A=20= =20=20=20=20=20=20=20=20cancel=20autovacuum=20worker=20processes,=20= which=20are=20otherwise=20considered=0A=20=20=20=20=20=20=20=20=20= superuser=20backends.=0A+=20=20=20=20=20=20=20=20If=20= message=20is=20specified=20and=20non-empty,=20= this=0A+=20=20=20=20=20=20=20=20string=20will=20be=20passed=20as=20= additional=20message=20in=20ERROR=20text=20for=0A+=20=20=20=20=20=20=20=20= canceled=20backend.=0A=20=20=20=20=20=20=20=20=0A=20=20=20= =20=20=20=20=0A=20=0A@@=20-225,7=20+228,7=20@@=0A=20=20=20=20=20=20= =20=20=20=0A=20=20=20=20=20=20=20=20=20=20= pg_terminate_backend=0A=20=20=20=20=20=20=20=20=20= =0A-=20=20=20=20=20=20=20=20= pg_terminate_backend=20(=20= pid=20integer,=20= timeout=20bigint=20= DEFAULT=200=20)=0A+=20=20=20=20=20=20= =20=20pg_terminate_backend=20(=20= pid=20integer,=20= timeout=20bigint=20= DEFAULT=200,=20= message=20test=20= DEFAULT=20'')=0A=20=20=20=20=20=20=20= =20=20boolean=0A=20=20=20=20=20=20=20=20= =0A=20=20=20=20=20=20=20=20=0A@@=20-249,6=20+252,9=20@@=0A=20= =20=20=20=20=20=20=20=20the=20process=20is=20terminated,=20the=20= function=0A=20=20=20=20=20=20=20=20=20returns=20true.=20= =20On=20timeout,=20a=20warning=20is=20emitted=20and=0A=20=20=20=20=20=20=20= =20=20false=20is=20returned.=0A+=20=20=20=20=20=20=20=20= If=20message=20is=20specified=20and=20non-empty,=20= this=0A+=20=20=20=20=20=20=20=20string=20will=20be=20passed=20as=20= additional=20message=20in=20FATAL=20text=20for=0A+=20=20=20=20=20=20=20=20= terminated=20backend.=0A=20=20=20=20=20=20=20=20=0A=20=20=20= =20=20=20=20=0A=20=20=20=20=20=20=0Adiff=20--git=20= a/src/backend/catalog/system_functions.sql=20= b/src/backend/catalog/system_functions.sql=0Aindex=20= eb9e31ae1bf..5e2c1386193=20100644=0A---=20= a/src/backend/catalog/system_functions.sql=0A+++=20= b/src/backend/catalog/system_functions.sql=0A@@=20-400,7=20+400,12=20@@=20= CREATE=20OR=20REPLACE=20FUNCTION=0A=20=20=20PARALLEL=20SAFE;=0A=20=0A=20= CREATE=20OR=20REPLACE=20FUNCTION=0A-=20=20pg_terminate_backend(pid=20= integer,=20timeout=20int8=20DEFAULT=200)=0A+=20=20pg_cancel_backend(pid=20= integer,=20msg=20text=20DEFAULT=20'')=0A+=20=20RETURNS=20boolean=20= STRICT=20VOLATILE=20LANGUAGE=20INTERNAL=20AS=20'pg_cancel_backend'=0A+=20= =20PARALLEL=20SAFE;=0A+=0A+CREATE=20OR=20REPLACE=20FUNCTION=0A+=20=20= pg_terminate_backend(pid=20integer,=20timeout=20int8=20DEFAULT=200,=20= msg=20text=20DEFAULT=20'')=0A=20=20=20RETURNS=20boolean=20STRICT=20= VOLATILE=20LANGUAGE=20INTERNAL=20AS=20'pg_terminate_backend'=0A=20=20=20= PARALLEL=20SAFE;=0A=20=0Adiff=20--git=20a/src/backend/storage/ipc/ipci.c=20= b/src/backend/storage/ipc/ipci.c=0Aindex=201f7e933d500..9f50adf030c=20= 100644=0A---=20a/src/backend/storage/ipc/ipci.c=0A+++=20= b/src/backend/storage/ipc/ipci.c=0A@@=20-52,6=20+52,7=20@@=0A=20#include=20= "storage/sinvaladt.h"=0A=20#include=20"utils/guc.h"=0A=20#include=20= "utils/injection_point.h"=0A+#include=20"utils/backend_msg.h"=0A=20=0A=20= /*=20GUCs=20*/=0A=20int=09=09=09shared_memory_type=20=3D=20= DEFAULT_SHARED_MEMORY_TYPE;=0A@@=20-140,6=20+141,7=20@@=20= CalculateShmemSize(void)=0A=20=09size=20=3D=20add_size(size,=20= SlotSyncShmemSize());=0A=20=09size=20=3D=20add_size(size,=20= AioShmemSize());=0A=20=09size=20=3D=20add_size(size,=20= WaitLSNShmemSize());=0A+=09size=20=3D=20add_size(size,=20= BackendStatusShmemSize());=0A=20=09size=20=3D=20add_size(size,=20= LogicalDecodingCtlShmemSize());=0A=20=0A=20=09/*=20include=20additional=20= requested=20shmem=20from=20preload=20libraries=20*/=0A@@=20-327,6=20= +329,7=20@@=20CreateOrAttachShmemStructs(void)=0A=20=09= InjectionPointShmemInit();=0A=20=09AioShmemInit();=0A=20=09= WaitLSNShmemInit();=0A+=09BackendMsgShmemInit();=0A=20=09= LogicalDecodingCtlShmemInit();=0A=20}=0A=20=0Adiff=20--git=20= a/src/backend/storage/ipc/signalfuncs.c=20= b/src/backend/storage/ipc/signalfuncs.c=0Aindex=20= 6f7759cd720..b66aadc7c0e=20100644=0A---=20= a/src/backend/storage/ipc/signalfuncs.c=0A+++=20= b/src/backend/storage/ipc/signalfuncs.c=0A@@=20-25,6=20+25,8=20@@=0A=20= #include=20"storage/procarray.h"=0A=20#include=20"utils/acl.h"=0A=20= #include=20"utils/fmgrprotos.h"=0A+#include=20"utils/builtins.h"=0A= +#include=20"utils/backend_msg.h"=0A=20=0A=20=0A=20/*=0A@@=20-48,7=20= +50,7=20@@=0A=20#define=20SIGNAL_BACKEND_NOSUPERUSER=203=0A=20#define=20= SIGNAL_BACKEND_NOAUTOVAC=204=0A=20static=20int=0A-pg_signal_backend(int=20= pid,=20int=20sig)=0A+pg_signal_backend(int=20pid,=20int=20sig,=20const=20= char=20*msg)=0A=20{=0A=20=09PGPROC=09=20=20=20*proc=20=3D=20= BackendPidGetProc(pid);=0A=20=0A@@=20-111,6=20+113,15=20@@=20= pg_signal_backend(int=20pid,=20int=20sig)=0A=20=09=20*=20too=20unlikely=20= to=20worry=20about.=0A=20=09=20*/=0A=20=0A+=09if=20(msg=20!=3D=20NULL=20= &&=20msg[0]=20!=3D=20'\0')=0A+=09{=0A+=09=09int=09=09r=20=3D=20= BackendMsgSet(pid,=20msg);=0A+=0A+=09=09if=20(r=20!=3D=20-1=20&&=20r=20= !=3D=20strlen(msg))=0A+=09=09=09ereport(NOTICE,=0A+=09=09=09=09=09= (errmsg("message=20is=20too=20long,=20truncated=20to=20%d",=20r)));=0A+=09= }=0A+=0A=20=09/*=20If=20we=20have=20setsid(),=20signal=20the=20backend's=20= whole=20process=20group=20*/=0A=20#ifdef=20HAVE_SETSID=0A=20=09if=20= (kill(-pid,=20sig))=0A@@=20-132,10=20+143,10=20@@=20= pg_signal_backend(int=20pid,=20int=20sig)=0A=20=20*=0A=20=20*=20Note=20= that=20only=20superusers=20can=20signal=20superuser-owned=20processes.=0A= =20=20*/=0A-Datum=0A-pg_cancel_backend(PG_FUNCTION_ARGS)=0A+static=20= Datum=0A+pg_cancel_backend_internal(pid_t=20pid,=20const=20char=20*msg)=0A= =20{=0A-=09int=09=09=09r=20=3D=20pg_signal_backend(PG_GETARG_INT32(0),=20= SIGINT);=0A+=09int=09=09=09r=20=3D=20pg_signal_backend(pid,=20SIGINT,=20= msg);=0A=20=0A=20=09if=20(r=20=3D=3D=20SIGNAL_BACKEND_NOSUPERUSER)=0A=20=09= =09ereport(ERROR,=0A@@=20-161,6=20+172,17=20@@=20= pg_cancel_backend(PG_FUNCTION_ARGS)=0A=20=09PG_RETURN_BOOL(r=20=3D=3D=20= SIGNAL_BACKEND_SUCCESS);=0A=20}=0A=20=0A+Datum=20= pg_cancel_backend(PG_FUNCTION_ARGS)=0A+{=0A+=09int=09=09=09pid;=0A+=09= char=09=20=20=20*msg;=0A+=0A+=09pid=20=3D=20PG_GETARG_INT32(0);=0A+=09= msg=20=3D=20text_to_cstring(PG_GETARG_TEXT_PP(1));=0A+=0A+=09return=20= pg_cancel_backend_internal(pid,=20msg);=0A+}=0A+=0A=20/*=0A=20=20*=20= Wait=20until=20there=20is=20no=20backend=20process=20with=20the=20given=20= PID=20and=20return=20true.=0A=20=20*=20On=20timeout,=20a=20warning=20is=20= emitted=20and=20false=20is=20returned.=0A@@=20-233,22=20+255,17=20@@=20= pg_wait_until_termination(int=20pid,=20int64=20timeout)=0A=20=20*=0A=20=20= *=20Note=20that=20only=20superusers=20can=20signal=20superuser-owned=20= processes.=0A=20=20*/=0A-Datum=0A-pg_terminate_backend(PG_FUNCTION_ARGS)=0A= +static=20Datum=0A+pg_terminate_backend_internal(int=20pid,=20int=20= timeout,=20const=20char=20*msg)=0A=20{=0A-=09int=09=09=09pid;=0A=20=09= int=09=09=09r;=0A-=09int=09=09=09timeout;=09=09/*=20milliseconds=20*/=0A= -=0A-=09pid=20=3D=20PG_GETARG_INT32(0);=0A-=09timeout=20=3D=20= PG_GETARG_INT64(1);=0A=20=0A=20=09if=20(timeout=20<=200)=0A=20=09=09= ereport(ERROR,=0A=20=09=09=09=09= (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),=0A=20=09=09=09=09=20= errmsg("\"timeout\"=20must=20not=20be=20negative")));=0A=20=0A-=09r=20=3D=20= pg_signal_backend(pid,=20SIGTERM);=0A+=09r=20=3D=20= pg_signal_backend(pid,=20SIGTERM,=20msg);=0A=20=0A=20=09if=20(r=20=3D=3D=20= SIGNAL_BACKEND_NOSUPERUSER)=0A=20=09=09ereport(ERROR,=0A@@=20-278,6=20= +295,19=20@@=20pg_terminate_backend(PG_FUNCTION_ARGS)=0A=20=09=09= PG_RETURN_BOOL(r=20=3D=3D=20SIGNAL_BACKEND_SUCCESS);=0A=20}=0A=20=0A= +Datum=20pg_terminate_backend(PG_FUNCTION_ARGS)=0A+{=0A+=09int=20pid;=0A= +=09int=20timeout;=20/*=20milliseconds=20*/=0A+=09char=20*msg;=0A+=0A+=09= pid=20=3D=20PG_GETARG_INT32(0);=0A+=09timeout=20=3D=20= PG_GETARG_INT64(1);=0A+=09msg=20=3D=20= text_to_cstring(PG_GETARG_TEXT_PP(2));=0A+=0A+=09return=20= pg_terminate_backend_internal(pid,=20timeout,=20msg);=0A+}=0A+=0A=20/*=0A= =20=20*=20Signal=20to=20reload=20the=20database=20configuration=0A=20=20= *=0Adiff=20--git=20a/src/backend/tcop/postgres.c=20= b/src/backend/tcop/postgres.c=0Aindex=20b4a8d2f3a1c..3c6d285a4dc=20= 100644=0A---=20a/src/backend/tcop/postgres.c=0A+++=20= b/src/backend/tcop/postgres.c=0A@@=20-81,6=20+81,7=20@@=0A=20#include=20= "utils/timeout.h"=0A=20#include=20"utils/timestamp.h"=0A=20#include=20= "utils/varlena.h"=0A+#include=20"utils/backend_msg.h"=0A=20=0A=20/*=20= ----------------=0A=20=20*=09=09global=20variables=0A@@=20-3356,9=20= +3357,22=20@@=20ProcessInterrupts(void)=0A=20=09=09=09proc_exit(0);=0A=20= =09=09}=0A=20=09=09else=0A+=09=09{=0A+=09=09=09if=20(BackendMsgIsSet())=0A= +=09=09=09{=0A+=09=09=09=09char=20msg[BACKEND_MSG_MAX_LEN];=0A+=0A+=09=09= =09=09BackendMsgGet(msg,=20sizeof(msg));=0A+=0A+=09=09=09=09= ereport(FATAL,=0A+=09=09=09=09=09=09(errcode(ERRCODE_ADMIN_SHUTDOWN),=0A= +=09=09=09=09=09=09errmsg("terminating=20connection=20due=20to=20= administrator=20command:=20%s",=20msg)));=0A+=09=09=09}=0A+=0A=20=09=09=09= ereport(FATAL,=0A=20=09=09=09=09=09(errcode(ERRCODE_ADMIN_SHUTDOWN),=0A=20= =09=09=09=09=09=20errmsg("terminating=20connection=20due=20to=20= administrator=20command")));=0A+=09=09}=0A=20=09}=0A=20=0A=20=09if=20= (CheckClientConnectionPending)=0A@@=20-3466,9=20+3480,21=20@@=20= ProcessInterrupts(void)=0A=20=09=09if=20(!DoingCommandRead)=0A=20=09=09{=0A= =20=09=09=09LockErrorCleanup();=0A-=09=09=09ereport(ERROR,=0A-=09=09=09=09= =09(errcode(ERRCODE_QUERY_CANCELED),=0A-=09=09=09=09=09=20= errmsg("canceling=20statement=20due=20to=20user=20request")));=0A+=0A+=09= =09=09if=20(BackendMsgIsSet())=0A+=09=09=09{=0A+=09=09=09=09char=20= msg[BACKEND_MSG_MAX_LEN];=0A+=0A+=09=09=09=09BackendMsgGet(msg,=20= sizeof(msg));=0A+=0A+=09=09=09=09ereport(ERROR,=0A+=09=09=09=09=09=09= (errcode(ERRCODE_QUERY_CANCELED),=0A+=09=09=09=09=09=09=20= errmsg("canceling=20statement=20due=20to=20user=20request:=20%s",=20= msg)));=0A+=09=09=09}=0A+=09=09=09else=0A+=09=09=09=09ereport(ERROR,=0A+=09= =09=09=09=09=09(errcode(ERRCODE_QUERY_CANCELED),=0A+=09=09=09=09=09=09=20= errmsg("canceling=20statement=20due=20to=20user=20request")));=0A=20=09=09= }=0A=20=09}=0A=20=0Adiff=20--git=20a/src/backend/utils/init/postinit.c=20= b/src/backend/utils/init/postinit.c=0Aindex=203f401faf3de..debf6da4a7b=20= 100644=0A---=20a/src/backend/utils/init/postinit.c=0A+++=20= b/src/backend/utils/init/postinit.c=0A@@=20-69,6=20+69,7=20@@=0A=20= #include=20"utils/snapmgr.h"=0A=20#include=20"utils/syscache.h"=0A=20= #include=20"utils/timeout.h"=0A+#include=20"utils/backend_msg.h"=0A=20=0A= =20static=20HeapTuple=20GetDatabaseTuple(const=20char=20*dbname);=0A=20= static=20HeapTuple=20GetDatabaseTupleByOid(Oid=20dboid);=0A@@=20-902,6=20= +903,7=20@@=20InitPostgres(const=20char=20*in_dbname,=20Oid=20dboid,=0A=20= =09=09=09InitializeSystemUser(MyClientConnectionInfo.authn_id,=0A=20=09=09= =09=09=09=09=09=09=20hba_authname(MyClientConnectionInfo.auth_method));=0A= =20=09=09am_superuser=20=3D=20superuser();=0A+=09=09= BackendMsgInit(MyProcNumber);=0A=20=09}=0A=20=0A=20=09/*=20Report=20any=20= SSL/GSS=20details=20for=20the=20session.=20*/=0Adiff=20--git=20= a/src/backend/utils/misc/Makefile=20b/src/backend/utils/misc/Makefile=0A= index=20f142d17178b..5494994669f=20100644=0A---=20= a/src/backend/utils/misc/Makefile=0A+++=20= b/src/backend/utils/misc/Makefile=0A@@=20-32,7=20+32,8=20@@=20OBJS=20=3D=20= \=0A=20=09stack_depth.o=20\=0A=20=09superuser.o=20\=0A=20=09timeout.o=20= \=0A-=09tzparser.o=0A+=09tzparser.o=20\=0A+=09backend_msg.o=0A=20=0A=20#=20= This=20location=20might=20depend=20on=20the=20installation=20= directories.=20Therefore=0A=20#=20we=20can't=20substitute=20it=20into=20= pg_config.h.=0Adiff=20--git=20a/src/backend/utils/misc/backend_msg.c=20= b/src/backend/utils/misc/backend_msg.c=0Anew=20file=20mode=20100644=0A= index=2000000000000..b7c7d30e049=0A---=20/dev/null=0A+++=20= b/src/backend/utils/misc/backend_msg.c=0A@@=20-0,0=20+1,156=20@@=0A= +/*--------------------------------------------------------------------=0A= +=20*=20backend_msg.h=0A+=20*=0A+=20*=20Utility=20to=20pass=20additional=20= message=20to=20backend=20processes.=0A+=20*=20Ex:=20cancel=20or=20= terminate=20messages=0A+=20*=0A+=20*=20Portions=20Copyright=20(c)=20= 1996-2025,=20PostgreSQL=20Global=20Development=20Group=0A+=20*=20= Portions=20Copyright=20(c)=201994,=20Regents=20of=20the=20University=20= of=20California=0A+=20*=0A+=20*=20src/include/utils/misc/backend_msg.c=0A= +=20*=0A+=20= *--------------------------------------------------------------------=0A= +=20*/=0A+=0A+#include=20"postgres.h"=0A+=0A+#include=20"miscadmin.h"=0A= +#include=20"storage/shmem.h"=0A+#include=20"storage/spin.h"=0A+#include=20= "storage/ipc.h"=0A+#include=20"utils/backend_msg.h"=0A+=0A+typedef=20= struct=20{=0A+=09pid_t=20pid;=0A+=09slock_t=20lock;=0A+=09char=20= msg[BACKEND_MSG_MAX_LEN];=0A+}=20BackendMsgSlot;=0A+=0A+=0A+static=20= BackendMsgSlot=20*BackendMsgSlots;=0A+static=20BackendMsgSlot=20= *MyBackendMsgSlot;=0A+=0A+static=20void=0A+backend_msg_slot_clean(int=20= code,=20Datum=20arg)=0A+{=0A+=09(void)=20code;=0A+=09(void)=20arg;=0A+=0A= +=09Assert(MyBackendMsgSlot=20!=3D=20NULL);=0A+=0A+=09= SpinLockAcquire(&MyBackendMsgSlot->lock);=0A+=0A+=09= MyBackendMsgSlot->msg[0]=20=3D=20'\0';=0A+=09MyBackendMsgSlot->pid=20=3D=20= 0;=0A+=0A+=09SpinLockRelease(&MyBackendMsgSlot->lock);=0A+=0A+=09= MyBackendMsgSlot=20=3D=20NULL;=0A+}=0A+=0A+=0A+void=20= BackendMsgShmemInit(void)=0A+{=0A+=09Size=09size;=0A+=09bool=09found;=0A= +=0A+=09size=20=3D=20BackendMsgShmemSize();=0A+=09BackendMsgSlots=20=3D=20= ShmemInitStruct("BackendMsgSlots",=20size,=20&found);=0A+=0A+=09if=20= (found)=0A+=09=09return;=0A+=09=0A+=09memset(BackendMsgSlots,=200,=20= size);=0A+=0A+=09for=20(int=20i=20=3D=200;=20i=20<=20MaxBackends;=20++i)=0A= +=09=09SpinLockInit(&BackendMsgSlots[i].lock);=0A+}=0A+=0A+Size=0A= +BackendMsgShmemSize(void)=0A+{=0A+=09return=20mul_size(MaxBackends,=20= sizeof(BackendMsgSlot));=0A+}=0A+=0A+void=20BackendMsgInit(int=20id)=0A= +{=0A+=09BackendMsgSlot=09=09*slot;=0A+=0A+=09slot=20=3D=20= &BackendMsgSlots[id];=0A+=0A+=09slot->msg[0]=20=3D=20'\0';=0A+=09= slot->pid=20=3D=20MyProcPid;=0A+=0A+=09MyBackendMsgSlot=20=3D=20slot;=0A= +=0A+=09on_shmem_exit(backend_msg_slot_clean,=20Int32GetDatum(0)=20/*=20= not=20used=20*/);=0A+}=0A+=0A+int=20BackendMsgSet(pid_t=20pid,=20const=20= char=20*msg)=0A+{=0A+=09BackendMsgSlot=09=09*slot;=0A+=09int=09=09=09=09=09= len;=0A+=0A+=09if=20(msg=20=3D=3D=20NULL=20||=20msg[0]=20=3D=3D=20'\0')=0A= +=09=09return=200;=0A+=0A+=09for=20(int=20i=20=3D=200;=20i=20<=20= MaxBackends;=20++i)=0A+=09{=0A+=09=09slot=20=3D=20&BackendMsgSlots[i];=0A= +=0A+=09=09if=20(slot->pid=20=3D=3D=200=20||=20slot->pid=20!=3D=20pid)=0A= +=09=09=09continue;=0A+=0A+=09=09SpinLockAcquire(&slot->lock);=0A+=0A+=09= =09if=20(slot->pid=20!=3D=20pid)=0A+=09=09{=0A+=09=09=09= SpinLockRelease(&slot->lock);=0A+=09=09=09break;=0A+=09=09}=0A+=0A+=09=09= len=20=3D=20stpncpy(slot->msg,=20msg,=20sizeof(slot->msg)=20-=201)=20-=20= slot->msg;=0A+=09=09slot->msg[len]=20=3D=20'\0';=0A+=0A+=09=09= SpinLockRelease(&slot->lock);=0A+=0A+=09=09return=20len;=0A+=09}=0A+=0A+=09= ereport(LOG,=0A+=09=09=09(errmsg("Can't=20set=20message=20for=20missing=20= backend=20%ld,=20requested=20by=20%ld",=0A+=09=09=09=09(long)=20pid,=20= (long)=20MyProcPid)));=0A+=0A+=09return=20-1;=0A+}=0A+=0A+int=20= BackendMsgGet(char=20*buf,=20int=20max_len)=0A+{=0A+=09int=09=09len;=0A+=0A= +=09if=20(MyBackendMsgSlot=20=3D=3D=20NULL)=0A+=09=09return=200;=0A+=0A+=09= SpinLockAcquire(&MyBackendMsgSlot->lock);=0A+=0A+=09len=20=3D=20= strlcpy(buf,=20MyBackendMsgSlot->msg,=20max_len);=0A+=09= memset(MyBackendMsgSlot->msg,=20'\0',=20sizeof(MyBackendMsgSlot->msg));=0A= +=0A+=09SpinLockRelease(&MyBackendMsgSlot->lock);=0A+=0A+=09return=20= len;=0A+}=0A+=0A+bool=20BackendMsgIsSet(void)=0A+{=0A+=09bool=20result=20= =3D=20false;=0A+=0A+=09if=20(MyBackendMsgSlot=20=3D=3D=20NULL)=0A+=09=09= return=20false;=0A+=0A+=09SpinLockAcquire(&MyBackendMsgSlot->lock);=0A+=09= result=20=3D=20MyBackendMsgSlot->msg[0]=20!=3D=20'\0';=0A+=09= SpinLockRelease(&MyBackendMsgSlot->lock);=0A+=0A+=09return=20result;=0A= +}=0Adiff=20--git=20a/src/backend/utils/misc/meson.build=20= b/src/backend/utils/misc/meson.build=0Aindex=20232e74d0af9..831bf6c6bab=20= 100644=0A---=20a/src/backend/utils/misc/meson.build=0A+++=20= b/src/backend/utils/misc/meson.build=0A@@=20-1,6=20+1,7=20@@=0A=20#=20= Copyright=20(c)=202022-2026,=20PostgreSQL=20Global=20Development=20Group=0A= =20=0A=20backend_sources=20+=3D=20files(=0A+=20=20'backend_msg.c',=0A=20=20= =20'conffiles.c',=0A=20=20=20'guc.c',=0A=20=20=20'guc_funcs.c',=0Adiff=20= --git=20a/src/include/utils/backend_msg.h=20= b/src/include/utils/backend_msg.h=0Anew=20file=20mode=20100644=0Aindex=20= 00000000000..825bf7100e2=0A---=20/dev/null=0A+++=20= b/src/include/utils/backend_msg.h=0A@@=20-0,0=20+1,28=20@@=0A= +/*--------------------------------------------------------------------=0A= +=20*=20backend_msg.h=0A+=20*=0A+=20*=20Utility=20to=20pass=20additional=20= message=20to=20backend=20processes.=0A+=20*=20Ex:=20cancel=20or=20= terminate=20messages=0A+=20*=0A+=20*=20Portions=20Copyright=20(c)=20= 1996-2025,=20PostgreSQL=20Global=20Development=20Group=0A+=20*=20= Portions=20Copyright=20(c)=201994,=20Regents=20of=20the=20University=20= of=20California=0A+=20*=0A+=20*=20src/include/utils/backend_msg.h=0A+=20= *=0A+=20= *--------------------------------------------------------------------=0A= +=20*/=0A+=0A+#ifndef=20BACKEND_MSG_H=0A+#define=20BACKEND_MSG_H=0A+=0A= +#define=20BACKEND_MSG_MAX_LEN=20128=0A+=0A+extern=20void=20= BackendMsgShmemInit(void);=0A+extern=20Size=20BackendMsgShmemSize(void);=0A= +extern=20void=20BackendMsgInit(int=20id);=0A+extern=20int=20= BackendMsgSet(pid_t=20pid,=20const=20char=20*msg);=0A+extern=20int=20= BackendMsgGet(char=20*buf,=20int=20max_len);=0A+extern=20bool=20= BackendMsgIsSet(void);=0A+=0A+=0A+#endif=20/*=20BACKEND_MSG_H=20*/=0A= diff=20--git=20a/src/test/modules/test_misc/meson.build=20= b/src/test/modules/test_misc/meson.build=0Aindex=20= 6e8db1621a7..674675b7ce1=20100644=0A---=20= a/src/test/modules/test_misc/meson.build=0A+++=20= b/src/test/modules/test_misc/meson.build=0A@@=20-19,6=20+19,7=20@@=20= tests=20+=3D=20{=0A=20=20=20=20=20=20=20't/008_replslot_single_user.pl',=0A= =20=20=20=20=20=20=20't/009_log_temp_files.pl',=0A=20=20=20=20=20=20=20= 't/010_index_concurrently_upsert.pl',=0A+=20=20=20=20=20=20= 't/011_backend_msg.pl',=0A=20=20=20=20=20],=0A=20=20=20=20=20#=20The=20= injection=20points=20are=20cluster-wide,=20so=20disable=20installcheck=0A= =20=20=20=20=20'runningcheck':=20false,=0Adiff=20--git=20= a/src/test/modules/test_misc/t/011_backend_msg.pl=20= b/src/test/modules/test_misc/t/011_backend_msg.pl=0Anew=20file=20mode=20= 100644=0Aindex=2000000000000..795f3d55cfb=0A---=20/dev/null=0A+++=20= b/src/test/modules/test_misc/t/011_backend_msg.pl=0A@@=20-0,0=20+1,42=20= @@=0A+#=20Copyright=20(c)=202025,=20PostgreSQL=20Global=20Development=20= Group=0A+=0A+#=20Check=20that=20messages=20are=20passed=20to=20backends=20= by=0A+#=20pg_terminate_backend,=20pg_cancel_backend=0A+=0A+use=20strict;=0A= +use=20warnings=20FATAL=20=3D>=20'all';=0A+use=20= PostgreSQL::Test::Cluster;=0A+use=20PostgreSQL::Test::Utils;=0A+use=20= Test::More;=0A+=0A+my=20$node=20=3D=20= PostgreSQL::Test::Cluster->new('primary');=0A+$node->init();=0A= +$node->start;=0A+=0A+my=20($stdout,=20$stderr);=0A= +$node->psql('postgres',=0A+=09q[select=20= pg_terminate_backend(pg_backend_pid(),=200,=20'Have=20you=20seen=20my=20= coffee=20cup?');],=0A+=09stdout=20=3D>=20\$stdout,=20stderr=20=3D>=20= \$stderr);=0A+like($stderr,=20qr/Have=20you=20seen=20my=20coffee=20= cup\?/,=20"expected=20message=20to=20be=20passed");=0A+=0A+$stdout=20=3D=20= '';=0A+$stderr=20=3D=20'';=0A+$node->psql('postgres',=0A+=09q[select=20= pg_cancel_backend(pg_backend_pid(),=20'You=20have=20to=20wear=20some=20= ridiculous=20tie');],=0A+=09stdout=20=3D>=20\$stdout,=20stderr=20=3D>=20= \$stderr);=0A+like($stderr,=20qr/You=20have=20to=20wear=20some=20= ridiculous=20tie/,=20"expected=20message=20to=20be=20passed");=0A+=0A= +$stdout=20=3D=20'';=0A+$stderr=20=3D=20'';=0A+my=20$longstr=20=3D=20= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstu= vwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQ= RSTUVWXYZ";=0A+my=20$truncated=20=3D=20substr($longstr,=200,=20127);=0A= +$node->psql('postgres',=0A+=09qq[select=20= pg_terminate_backend(pg_backend_pid(),=200,=20'$longstr');],=0A+=09= stdout=20=3D>=20\$stdout,=20stderr=20=3D>=20\$stderr);=0A+like($stderr,=20= qr/NOTICE:=20=20message=20is=20too=20long,=20truncated=20to=20127/,=20= "NOTICE=20message=20should=20be=20created");=0A+like($stderr,=20= qr/\Q$truncated\E/,=20"expected=20truncated=20message=20(127=20chars)=20= to=20be=20passed");=0A+unlike($stderr,=20qr/\Q$longstr\E/,=20"full=20= message=20must=20not=20be=20passed");=0A+=0A+$node->stop;=0A+=0A= +done_testing();=0A--=20=0A2.43.0=0A=0A= --Apple-Mail=_090BCC24-D0A3-49F3-9E83-9FA4411ED2D4--