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 1wV0pR-001c7M-2X for pgsql-hackers@arkaria.postgresql.org; Thu, 04 Jun 2026 05:41:17 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wV0pQ-00510x-2G for pgsql-hackers@arkaria.postgresql.org; Thu, 04 Jun 2026 05:41:16 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wV0pQ-00510p-1E for pgsql-hackers@lists.postgresql.org; Thu, 04 Jun 2026 05:41:16 +0000 Received: from mail-oo1-xc33.google.com ([2607:f8b0:4864:20::c33]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wV0pO-00000001BRT-0UMT for pgsql-hackers@lists.postgresql.org; Thu, 04 Jun 2026 05:41:16 +0000 Received: by mail-oo1-xc33.google.com with SMTP id 006d021491bc7-69e06aaf0b2so256307eaf.1 for ; Wed, 03 Jun 2026 22:41:14 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1780551672; cv=none; d=google.com; s=arc-20240605; b=VRg1YQ4R8Pya72/N/7NHRzaCf6dY92dGepLCj95Ux7A3BQqmoce/RE6pS6IpWOganm AHrzlNvyjKWbeCZCYIIT7a4rjXJgNn1eRma14dppy/+kl3+jXeufuRIb+Kq7UyWa5wsZ JlTuGnV9ePgaOsWNs3gGwxs68TwT3+bTqZPaIzY60dIrYZAldhgSX6MrtQVMYPsAR6JT cjIICxWACu690qlvSldBpYIn1kOKUpdiQU175irjDPJKRRStZbqG/Np/GYj6lI8nDcpf LBiBB26hYsKVODgKiJFp/M9krP9L8HFydrt1fSCp4eMAz8pRNZ04qwVb9ngHGCY1s7KN eXOA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:dkim-signature; bh=Xj5E2eZwcQA//gnczC21tvKAF6SkIfPOAam5TqE0E6Q=; fh=VBxjLiB7qm5dvPJ7D7JRlLT0xhmgame4C8PqHk6OhsU=; b=lMNpoVzX8p6csiwllKUC1WCbT4xCPRbV0OR4OA3YpjB+mY7aagCWxFQTqACP4JKBPg tbpbFG9T2H1yPwGNgJnEKl7dJFYZp2OeMyQIImj6+3EPSm38e9EeCVBAtSOW8Cra4Uvu f85hnOESHiu6pg3qHeiNxL5TFOldUxNIdjYo9TlN/bxE80aqMbSLa0KkcRlaWE2UrH5k UOMInK1dOrH5ieK7tiosPVEXBne7YQtgJtggjs38Ad0gDAELNGt9pcgH0vQQd+z57a5o G7YejWs1devXA9dgDf633LMbcL1RD77K9P4qAzxVAUqLXwilDmDrS0+Q32HBqK/Yz3cO GCUQ==; darn=lists.postgresql.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1780551672; x=1781156472; darn=lists.postgresql.org; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=Xj5E2eZwcQA//gnczC21tvKAF6SkIfPOAam5TqE0E6Q=; b=fr7Snd8NJMr7hhE4HbzkL5iLX1YKc5dWGv+wPgrQJkImm0kWRiRgn6Ft4h2UBqMmZq lf9iy8f3Udda0Uj3d/2qf5SkpjsRNq5Z4pb0dQKYOToVb4I6GGvqkHOlFRCJpiE9LoKH hz25Xa9vb3YTdbpfFJpLmuXu4aR+xH3SdjBIsDZ9UH5qeOrX9cDNqu2X6GoWzawvjos/ H2r25+35IwzLXaCIQSxCfBBJC9dLTGNmJIHja9iLrgzzq4yAe8sY/vqLyKgPvCYSc/Gj PJhiyVOEKci80pJR76vWTukNKwdt4rBZbvSaEmofuOXX6LLzxTeABOUZhJeZLNE0kNTS Gy4w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780551672; x=1781156472; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=Xj5E2eZwcQA//gnczC21tvKAF6SkIfPOAam5TqE0E6Q=; b=QlTdZ8VwJfmZd7BdAoyY1U1sinG6RkCN6sds0/JC5pNr8hPlJssk/TCBoGuPuWM5kS ktZarTjR7p1oEdD2hqe00eQK2GqfDBQtQ0iJDXIHRTx6Zz5XQqhCMMszuy/32HtURLcr g2ygm3D+DCWicDgo8zSy1ddDIB/DLEMg/IeJLdpABXSmekeI3rpljZNRgl2znGY6vxCb vlYICqgC1cNe80VyxpvRfbV+1kN/Z0ztCZzKjbUSkbDMmPV5UtpSEOIj1gEEm31u3BYq SZZOYqHPU43RqaM3RjfFk0HFvKGOTMe9yU6xl36HdGTGHZWWlcu1ewKcxbl8TFt4MpME Blhw== X-Forwarded-Encrypted: i=1; AFNElJ8pQPR2vfW4OkkDLRzLoNfWyBPRFsZg0plg8lh2lArmu0wCNs/aimLtQRB8wbMdS9XVxro5OLWGV6omKl8g@lists.postgresql.org X-Gm-Message-State: AOJu0YwADrOovC/MOALM8kI0Psk0zHAfr1BbQAuHq5U/lnEr+Z4Wqb86 OdmmR7hRLhANG05Lig50uw8k6434SczOFSFN3RvPrxMGDqEheBESrADE5te3pE7APpvkt7F6iUm rBQO9MNw+2+ALqJwfs1FyY9Mk2fGlcQY= X-Gm-Gg: Acq92OHxUCVd3RwAtT9EL6z3bDBPujQ1gVZwzTCWLfBfNUw9cjBMXxjEWiSlZ/wHx6t xf/pKqPSkefAapP/HADoThF5y/NeuBxf2PzqJJ0rDLUcPFxg51YXdZIL8lxcYuM+FrwaYgtMz5Y uaJvW7jMEg6H9++yi1S2Wil1ZxLlz7x5Qld7Jp+OigORWRnF4AnTfWCYVWCZz7qALO6DMSBhgqp bA8Tu5eZNr5M5R1bWeWIuq0LzZQQyjniEhILeuJUEPBzJGehB5prD+g6C/WSrsMzC/hNeeM920k x15OEjJmjIvqAedm+18kLdVECGHirnwT1HYP+BpgfLbWgH815svUqtbNsiyd1w== X-Received: by 2002:a05:6820:5494:b0:69e:3ddf:c0af with SMTP id 006d021491bc7-69e4808f8b8mr2928510eaf.40.1780551672131; Wed, 03 Jun 2026 22:41:12 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: From: JoongHyuk Shin Date: Thu, 4 Jun 2026 14:41:01 +0900 X-Gm-Features: AVHnY4L7LDjnvpY9pJvzQVRYKQZWTuaBc95QISBcu7A91UII-svWXXxphZeyPYk Message-ID: Subject: Re: [PATCH] Don't call ereport(ERROR) from recovery target GUC assign hooks To: scott@scottray.io Cc: Fujii Masao , Michael Paquier , pgsql-hackers@lists.postgresql.org Content-Type: multipart/alternative; boundary="000000000000ebf59d065366fd40" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --000000000000ebf59d065366fd40 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Thanks for the patch. I went through 'v1-0001-Report-....patch' and have a few observations to share. * Function structure: the recovery_target_* set has been historically stable, so array + loop abstraction adds limited value; function size grows ~34% (32 -> 43 lines) for one line of savings on a hypothetical sixth GUC, while the closest precedent (archive_command / archive_library in pgarch.c) is a hard-coded literal. * errhint vs errdetail: errhint("At most one of %s can be set.") reads more like a constraint than an action hint. The closest precedent, archive_command / archive_library in pgarch.c (ProcessPgArchInterrupts() / LoadArchiveLibrary()), keeps the enumeration in errdetail and omits errhint entirely. * TAP regex: the added like() uses [^"]+ for the values, which passes regardless of the actual value. Using quotemeta on the expected values would verify the actual content, and anchoring would also avoid accidentally matching the same tokens inside errhint. On the reload trap: I reproduced this on master and confirmed it's there exactly as you noted. ALTER SYSTEM doesn't trigger the assign hook; it just writes to postgresql.auto.conf, so the trap window is intrinsic to PGC_POSTMASTER + ALTER SYSTEM. A separate follow-up patch in the reload path feels natural. --=20 JH Shin On Mon, Jun 1, 2026 at 6:11=E2=80=AFAM Scott Ray wrote: > Thanks for the patch. I've attached v1-0001 (atop v4) addressing the > UX and test-coverage items below. Happy to rework or fold in however > you prefer. > > 1. There's a configuration trap in master and in this branch that > could be prevented using something very similar to > CheckRecoveryTargetConflicts to check pending GUCs: > > psql -c "ALTER SYSTEM SET recovery_target_xid TO '700'" > psql -c "ALTER SYSTEM SET recovery_target_time TO '2026-01-01 > 00:00:00'" > pg_ctl reload > > The log shows: > > LOG: received SIGHUP, reloading configuration files > LOG: parameter "recovery_target_xid" cannot be changed without > restarting the server > LOG: parameter "recovery_target_time" cannot be changed without > restarting the server > LOG: configuration file "postgresql.auto.conf" contains errors; > unaffected changes were applied > > pg_settings shows: > > postgres=3D# SELECT name, setting, pending_restart FROM pg_settings > WHERE name LIKE 'recovery_target%' AND pending_restart; > name | setting | pending_restart > ---------------------+---------+----------------- > recovery_target_time | | t > recovery_target_xid | | t > > The db runs fine until the next restart, maybe hours later: > > FATAL: multiple recovery targets specified > DETAIL: At most one of "recovery_target", "recovery_target_lsn", > "recovery_target_name", "recovery_target_time", > "recovery_target_xid" can be set. > > Is it worth a follow-up to report the conflict early and loud? > > 2. There's an opportunity to provide a better UX by reporting which > flags were set and what the values were, so that the user doesn't have > to search config files or other logs to find this info. For instance, > in the postgresql.auto.conf scenario above, instead of: > > DETAIL: At most one of "recovery_target", "recovery_target_lsn", > "recovery_target_name", "recovery_target_time", > "recovery_target_xid" can be set. > > The operator could see: > > DETAIL: The following recovery target parameters are set: > "recovery_target_time" =3D "2026-01-01 00:00:00", > "recovery_target_xid" =3D "700". > HINT: At most one of "recovery_target", "recovery_target_lsn", > "recovery_target_name", "recovery_target_time", > "recovery_target_xid" can be set. > > 3. 003_recovery_targets.pl:339 currently tests recovery_target_xid's > cleared-then-set behavior. The patch adds the same coverage for the > other four recovery_target_* GUCs. > > > -- > Scott Ray > --000000000000ebf59d065366fd40 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Thanks for the patch. =C2=A0
I went through 'v1-000= 1-Report-....patch'
and have a few observations to share.

* = Function structure: the recovery_target_* set has been
=C2=A0 historical= ly stable, so array + loop abstraction adds limited
=C2=A0 value; functi= on size grows ~34% (32 -> 43 lines) for one line of
=C2=A0 savings on= a hypothetical sixth GUC, while the closest precedent
=C2=A0 (archive_c= ommand / archive_library in pgarch.c) is a hard-coded literal.

* err= hint vs errdetail: errhint("At most one of %s can be set.")
= =C2=A0 reads more like a constraint than an action hint.=C2=A0 The closest<= br>=C2=A0 precedent, archive_command / archive_library in pgarch.c
=C2= =A0 (ProcessPgArchInterrupts() / LoadArchiveLibrary()), keeps the
=C2=A0= enumeration in errdetail and omits errhint entirely.

* TAP regex: t= he added like() uses [^"]+ for the values, which
=C2=A0 passes rega= rdless of the actual value.=C2=A0 Using quotemeta on the
=C2=A0 expected= values would verify the actual content, and anchoring
=C2=A0 would also= avoid accidentally matching the same tokens inside
=C2=A0 errhint.
<= br>On the reload trap:
I reproduced this on master and confirmed it'= ;s there exactly as you noted. =C2=A0
ALTER SYSTEM doesn't trigger t= he assign hook;
it just writes to postgresql.auto.conf,
so the trap= window is intrinsic to PGC_POSTMASTER + ALTER SYSTEM. =C2=A0
A separate= follow-up patch in the reload path feels natural.

--
JH Shin
On Mon, Jun 1, 2026 at 6:11=E2=80=AFAM Scott Ray <scott@scottray.io> wrote:
Thanks for the patch.=C2= =A0 I've attached v1-0001 (atop v4) addressing the
UX and test-coverage items below.=C2=A0 Happy to rework or fold in however<= br> you prefer.

1. There's a configuration trap in master and in this branch that
could be prevented using something very similar to
CheckRecoveryTargetConflicts to check pending GUCs:

=C2=A0 =C2=A0 psql -c "ALTER SYSTEM SET recovery_target_xid TO '70= 0'"
=C2=A0 =C2=A0 psql -c "ALTER SYSTEM SET recovery_target_time TO '2= 026-01-01 00:00:00'"
=C2=A0 =C2=A0 pg_ctl reload

The log shows:

=C2=A0 =C2=A0 LOG:=C2=A0 received SIGHUP, reloading configuration files
=C2=A0 =C2=A0 LOG:=C2=A0 parameter "recovery_target_xid" cannot b= e changed without restarting the server
=C2=A0 =C2=A0 LOG:=C2=A0 parameter "recovery_target_time" cannot = be changed without restarting the server
=C2=A0 =C2=A0 LOG:=C2=A0 configuration file "postgresql.auto.conf"= ; contains errors; unaffected changes were applied

pg_settings shows:

=C2=A0 =C2=A0 postgres=3D# SELECT name, setting, pending_restart FROM pg_se= ttings
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 WHERE name LIKE = 9;recovery_target%' AND pending_restart;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 name=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0| setting | pending_restart
=C2=A0 =C2=A0 ---------------------+---------+-----------------
=C2=A0 =C2=A0 =C2=A0recovery_target_time |=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0| t
=C2=A0 =C2=A0 =C2=A0recovery_target_xid=C2=A0 |=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0| t

The db runs fine until the next restart, maybe hours later:

=C2=A0 =C2=A0 FATAL:=C2=A0 multiple recovery targets specified
=C2=A0 =C2=A0 DETAIL:=C2=A0 At most one of "recovery_target", &qu= ot;recovery_target_lsn",
=C2=A0 =C2=A0 "recovery_target_name", "recovery_target_time&= quot;,
=C2=A0 =C2=A0 "recovery_target_xid" can be set.

Is it worth a follow-up to report the conflict early and loud?

2. There's an opportunity to provide a better UX by reporting which
flags were set and what the values were, so that the user doesn't have<= br> to search config files or other logs to find this info.=C2=A0 For instance,=
in the postgresql.auto.conf scenario above, instead of:

=C2=A0 =C2=A0 DETAIL:=C2=A0 At most one of "recovery_target", &qu= ot;recovery_target_lsn",
=C2=A0 =C2=A0 "recovery_target_name", "recovery_target_time&= quot;,
=C2=A0 =C2=A0 "recovery_target_xid" can be set.

The operator could see:

=C2=A0 =C2=A0 DETAIL:=C2=A0 The following recovery target parameters are se= t:
=C2=A0 =C2=A0 "recovery_target_time" =3D "2026-01-01 00:00:0= 0",
=C2=A0 =C2=A0 "recovery_target_xid" =3D "700".
=C2=A0 =C2=A0 HINT:=C2=A0 At most one of "recovery_target", "= ;recovery_target_lsn",
=C2=A0 =C2=A0 "recovery_target_name", "recovery_target_time&= quot;,
=C2=A0 =C2=A0 "recovery_target_xid" can be set.

3. 003_recovery_targets.pl:339 currently tests recovery_target= _xid's
cleared-then-set behavior.=C2=A0 The patch adds the same coverage for the other four recovery_target_* GUCs.


--
Scott Ray
--000000000000ebf59d065366fd40--