issue with synchronized_standby_slots
Hi,
With PG 17.5 and using logical replication failover slots.
When trying to change the value of synchronized_standby_slots, node2 was
not running then the error * invalid value for parameter
"synchronized_standby_slots": "node1,node2" *was generated.
The problem is that statement were affected by this and they can't execute.
STATEMENT: select service_period,sp1_0.address_line_1 from tbl1 where
sp1_0.vn=$1 order by sp1_0.start_of_period
2025-08-24 13:14:29.417 CEST [848477]: [1-1] user=,db=,client=,application=
ERROR: invalid value for parameter "synchronized_standby_slots":
"node1,node2"
2025-08-24 13:14:29.417 CEST [848477]: [2-1] user=,db=,client=,application=
DETAIL: replication slot "s029054a" does not exist
2025-08-24 13:14:29.417 CEST [848477]: [3-1] user=,db=,client=,application=
CONTEXT: while setting parameter "synchronized_standby_slots" to
"node1,node2"
2025-08-24 13:14:29.418 CEST [777453]: [48-1]
user=,db=,client=,application= LOG: background worker "parallel worker"
(PID 848476) exited with exit code 1
2025-08-24 13:14:29.418 CEST [777453]: [49-1]
user=,db=,client=,application= LOG: background worker "parallel worker"
(PID 848477) exited with exit code 1
Is this issue already observed
Thanks for your feedback
Fabrice
On Thursday, September 4, 2025 9:27 PM Fabrice Chapuis <fabrice636861@gmail.com> wrote:
With PG 17.5 and using logical replication failover slots. When trying to
change the value of synchronized_standby_slots, node2 was not running then the
error invalid value for parameter "synchronized_standby_slots": "node1,node2"
was generated. The problem is that statement were affected by this and they
can't execute.STATEMENT: select service_period,sp1_0.address_line_1 from tbl1 where http://sp1_0.vn=$1 order by sp1_0.start_of_period
2025-08-24 13:14:29.417 CEST [848477]: [1-1] user=,db=,client=,application= ERROR: invalid value for parameter "synchronized_standby_slots": "node1,node2"
2025-08-24 13:14:29.417 CEST [848477]: [2-1] user=,db=,client=,application= DETAIL: replication slot "s029054a" does not exist
2025-08-24 13:14:29.417 CEST [848477]: [3-1] user=,db=,client=,application= CONTEXT: while setting parameter "synchronized_standby_slots" to "node1,node2"
2025-08-24 13:14:29.418 CEST [777453]: [48-1] user=,db=,client=,application= LOG: background worker "parallel worker" (PID 848476) exited with exit code 1
2025-08-24 13:14:29.418 CEST [777453]: [49-1] user=,db=,client=,application= LOG: background worker "parallel worker" (PID 848477) exited with exit code 1Is this issue already observed
Thank you for reporting this issue. It seems you've added a nonexistent slot to
synchronized_standby_slots before the server startup. The server does not verify
the existence of slots at startup due to the absence of slot shared information,
allowing the server to start successfully. However, when the parallel apply
worker starts, it re-verifies the GUC setting, resulting in the ERROR you saw.
I think this scenario is not necessarily a bug, as adding nonexistent slots to GUC is
disallowed. Such slots can block the logical failover slot's advancement,
increasing the risk of disk bloat due to WAL or dead rows, which is why we added
the ERROR. There are precedents for this kind of behavior, like
default_table_access_method and default_tablespace, which prevent queries if
invalid values are set before server startup.
To resolve the issue, you can remove the invalid slot from the GUC and add it
back after creating the physical slot.
I also thought about how to improve user experience for this, but it's not
feasible to verify slot existence at startup because replication has not been
restored to shared memory during GUC checks. Another option might be to simply
remove slot existence/type checks from GUC validation.
Best Regards,
Hou zj
Thanks for your reply Zhijie,
I understand that the error invalid value for parameter will be diplayed
in case of bad value for the GUC synchronized_standby_slots or if a standby
node configured is not up and running.
But the problem I noticed is that statements could not execute normally and
error code is returned to the applcation.
This append after an upgrade from PG 14 to PG 17.
I could try to reproduce the issue
Regards,
Fabrice
On Fri, Sep 5, 2025 at 6:07 AM Zhijie Hou (Fujitsu) <houzj.fnst@fujitsu.com>
wrote:
Show quoted text
On Thursday, September 4, 2025 9:27 PM Fabrice Chapuis <
fabrice636861@gmail.com> wrote:With PG 17.5 and using logical replication failover slots. When trying to
change the value of synchronized_standby_slots, node2 was not runningthen the
error invalid value for parameter "synchronized_standby_slots":
"node1,node2"
was generated. The problem is that statement were affected by this and
they
can't execute.
STATEMENT: select service_period,sp1_0.address_line_1 from tbl1 where
http://sp1_0.vn=$1 order by sp1_0.start_of_period
2025-08-24 13:14:29.417 CEST [848477]: [1-1]
user=,db=,client=,application= ERROR: invalid value for parameter
"synchronized_standby_slots": "node1,node2"2025-08-24 13:14:29.417 CEST [848477]: [2-1]
user=,db=,client=,application= DETAIL: replication slot "s029054a" does
not exist2025-08-24 13:14:29.417 CEST [848477]: [3-1]
user=,db=,client=,application= CONTEXT: while setting parameter
"synchronized_standby_slots" to "node1,node2"2025-08-24 13:14:29.418 CEST [777453]: [48-1]
user=,db=,client=,application= LOG: background worker "parallel worker"
(PID 848476) exited with exit code 12025-08-24 13:14:29.418 CEST [777453]: [49-1]
user=,db=,client=,application= LOG: background worker "parallel worker"
(PID 848477) exited with exit code 1Is this issue already observed
Thank you for reporting this issue. It seems you've added a nonexistent
slot to
synchronized_standby_slots before the server startup. The server does not
verify
the existence of slots at startup due to the absence of slot shared
information,
allowing the server to start successfully. However, when the parallel apply
worker starts, it re-verifies the GUC setting, resulting in the ERROR you
saw.I think this scenario is not necessarily a bug, as adding nonexistent
slots to GUC is
disallowed. Such slots can block the logical failover slot's advancement,
increasing the risk of disk bloat due to WAL or dead rows, which is why we
added
the ERROR. There are precedents for this kind of behavior, like
default_table_access_method and default_tablespace, which prevent queries
if
invalid values are set before server startup.To resolve the issue, you can remove the invalid slot from the GUC and add
it
back after creating the physical slot.I also thought about how to improve user experience for this, but it's not
feasible to verify slot existence at startup because replication has not
been
restored to shared memory during GUC checks. Another option might be to
simply
remove slot existence/type checks from GUC validation.Best Regards,
Hou zj
Hi,
On Sun, 7 Sept 2025 at 10:15, Fabrice Chapuis <fabrice636861@gmail.com>
wrote:
Thanks for your reply Zhijie,
I understand that the error invalid value for parameter will be diplayed
in case of bad value for the GUC synchronized_standby_slots or if a
standby node configured is not up and running.
But the problem I noticed is that statements could not execute normally
and error code is returned to the applcation.
This append after an upgrade from PG 14 to PG 17.
I could try to reproduce the issue
STATEMENT: select service_period,sp1_0.address_line_1 from tbl1 where
http://sp1_0.vn=$1 order by sp1_0.start_of_period
2025-08-24 13:14:29.417 CEST [848477]: [1-1]
user=,db=,client=,application= ERROR: invalid value for parameter
"synchronized_standby_slots": "node1,node2"2025-08-24 13:14:29.417 CEST [848477]: [2-1]
user=,db=,client=,application= DETAIL: replication slot "s029054a" does
not exist2025-08-24 13:14:29.417 CEST [848477]: [3-1]
user=,db=,client=,application= CONTEXT: while setting parameter
"synchronized_standby_slots" to "node1,node2"2025-08-24 13:14:29.418 CEST [777453]: [48-1]
user=,db=,client=,application= LOG: background worker "parallel worker"
(PID 848476) exited with exit code 12025-08-24 13:14:29.418 CEST [777453]: [49-1]
user=,db=,client=,application= LOG: background worker "parallel worker"
(PID 848477) exited with exit code 1Is this issue already observed
Recently we also hit this problem.
I think in a current state check_synchronized_standby_slots()
and validate_sync_standby_slots() functions are not very useful:
- When the hook is executed from postmaster it only checks
that synchronized_standby_slots contains a valid list, but doesn't check
that replication slots exists, because MyProc is NULL. It happens both, on
start and on reload.
- When executed from other backends set_config_with_handle() is called
with elevel = 0, and therefore elevel becomes DEBUG3, which results in no
useful error/warning messages.
There are a couple of places where check_synchronized_standby_slots()
failure is not ignored:
1. alter system set synchronized_standby_slots='invalid value';
2. Parallel workers, because RestoreGUCState()
calls set_config_option_ext()->set_config_with_handle() with elevel=ERROR.
As a result, parallel workers fail to start with the error.
With parallel workers it is actually even worse - we get the error even in
case of standby:
1. start standby with synchronized_standby_slots referring to non-existing
slots
2. SET parallel_setup_cost, parallel_tuple_cost,
and min_parallel_table_scan_size to 0
3. Run select * from pg_namespace; and observe following error:
ERROR: invalid value for parameter "synchronized_standby_slots": "a1,b1"
DETAIL: replication slot "a1" does not exist
CONTEXT: while setting parameter "synchronized_standby_slots" to "a1,b1"
parallel worker
We may argue a lot that invalid configuration must not be used, but the
thing is that the main problem being solved by synchronized_standby_slots
is delaying logical decoding at certains LSN until it was sent to enough
physical standby.
This feature must not affect normal queries, only logical replication.
Please find attached patch fixing a problem for parallel workers.
Regards,
--
Alexander Kukushkin
Attachments:
0001-Exclude-parallel-workers-when-validating-synchronize.patchtext/x-patch; charset=US-ASCII; name=0001-Exclude-parallel-workers-when-validating-synchronize.patchDownload
From d4dbac3669d96d40d56fe5e738da9a78a3fcfb47 Mon Sep 17 00:00:00 2001
From: Alexander Kukushkin <cyberdemn@gmail.com>
Date: Mon, 8 Sep 2025 11:16:54 +0200
Subject: [PATCH] Exclude parallel workers when validating
synchronized_standby_slots
If synchronized_standby_slots value is invalid parallel workers fail to
start with the following error:
ERROR: invalid value for parameter "synchronized_standby_slots": "a1,b1"
DETAIL: replication slot "a1" does not exist
CONTEXT: while setting parameter "synchronized_standby_slots" to "a1,b1"
Since the value can't be properly validated from postmaster process we
shouldn't fail in parallel workers either.
---
src/backend/replication/slot.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index a234e2ca9c1..76ce7a35a01 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -39,6 +39,7 @@
#include <unistd.h>
#include <sys/stat.h>
+#include "access/parallel.h"
#include "access/transam.h"
#include "access/xlog_internal.h"
#include "access/xlogrecovery.h"
@@ -2441,7 +2442,7 @@ validate_sync_standby_slots(char *rawname, List **elemlist)
{
GUC_check_errdetail("List syntax is invalid.");
}
- else if (MyProc)
+ else if (MyProc && !IsParallelWorker())
{
/*
* Check that each specified slot exist and is physical.
--
2.34.1
On Mon, Sep 8, 2025 at 6:26 PM Alexander Kukushkin <cyberdemn@gmail.com> wrote:
Hi,
On Sun, 7 Sept 2025 at 10:15, Fabrice Chapuis <fabrice636861@gmail.com> wrote:
Thanks for your reply Zhijie,
I understand that the error invalid value for parameter will be diplayed in case of bad value for the GUC synchronized_standby_slots or if a standby node configured is not up and running.
But the problem I noticed is that statements could not execute normally and error code is returned to the applcation.
This append after an upgrade from PG 14 to PG 17.
I could try to reproduce the issueSTATEMENT: select service_period,sp1_0.address_line_1 from tbl1 where http://sp1_0.vn=$1 order by sp1_0.start_of_period
2025-08-24 13:14:29.417 CEST [848477]: [1-1] user=,db=,client=,application= ERROR: invalid value for parameter "synchronized_standby_slots": "node1,node2"
2025-08-24 13:14:29.417 CEST [848477]: [2-1] user=,db=,client=,application= DETAIL: replication slot "s029054a" does not exist
2025-08-24 13:14:29.417 CEST [848477]: [3-1] user=,db=,client=,application= CONTEXT: while setting parameter "synchronized_standby_slots" to "node1,node2"
2025-08-24 13:14:29.418 CEST [777453]: [48-1] user=,db=,client=,application= LOG: background worker "parallel worker" (PID 848476) exited with exit code 1
2025-08-24 13:14:29.418 CEST [777453]: [49-1] user=,db=,client=,application= LOG: background worker "parallel worker" (PID 848477) exited with exit code 1Is this issue already observed
Recently we also hit this problem.
I think in a current state check_synchronized_standby_slots() and validate_sync_standby_slots() functions are not very useful:
- When the hook is executed from postmaster it only checks that synchronized_standby_slots contains a valid list, but doesn't check that replication slots exists, because MyProc is NULL. It happens both, on start and on reload.
This looks quite problematic. If a non-existent slot is specified in
synchronized_standby_slots in postgresql.conf and the configuration file
is reloaded, no error is reported. This happens because the postmaster
cannot detect that the slot doesn't exist (since it has no MyProc).
As a result, synchronized_standby_slots in the postmaster is set to
that slot. New backends then inherit this setting from the postmaster,
while already running backends correctly detect that the slot doesn't
exist and fail to apply it.
This leads to an inconsistent state: the reload succeeds with no error,
but some backends apply the new setting while others do not.
That inconsistency seems like an issue.
To fix this, ISTM that the GUC check hook for synchronized_standby_slots
should be revised so it doesn't rely on MyProc or perform slot existence
checks there....
Regards,
--
Fujii Masao
On Mon, Sep 8, 2025 at 2:56 PM Alexander Kukushkin <cyberdemn@gmail.com> wrote:
Recently we also hit this problem.
I think in a current state check_synchronized_standby_slots() and validate_sync_standby_slots() functions are not very useful:
- When the hook is executed from postmaster it only checks that synchronized_standby_slots contains a valid list, but doesn't check that replication slots exists, because MyProc is NULL. It happens both, on start and on reload.
- When executed from other backends set_config_with_handle() is called with elevel = 0, and therefore elevel becomes DEBUG3, which results in no useful error/warning messages.There are a couple of places where check_synchronized_standby_slots() failure is not ignored:
1. alter system set synchronized_standby_slots='invalid value';
2. Parallel workers, because RestoreGUCState() calls set_config_option_ext()->set_config_with_handle() with elevel=ERROR. As a result, parallel workers fail to start with the error.With parallel workers it is actually even worse - we get the error even in case of standby:
1. start standby with synchronized_standby_slots referring to non-existing slots
2. SET parallel_setup_cost, parallel_tuple_cost, and min_parallel_table_scan_size to 0
3. Run select * from pg_namespace; and observe following error:
ERROR: invalid value for parameter "synchronized_standby_slots": "a1,b1"
DETAIL: replication slot "a1" does not exist
CONTEXT: while setting parameter "synchronized_standby_slots" to "a1,b1"
parallel worker
I see the same behaviour for default_table_access_method and
default_tablespace. For example, see failure cases:
postgres=# Alter system set default_table_access_method='missing';
ERROR: invalid value for parameter "default_table_access_method": "missing"
DETAIL: Table access method "missing" does not exist.
postgres=# SET parallel_setup_cost=0;
SET
postgres=# SET parallel_tuple_cost=0;
SET
postgres=# Set min_parallel_table_scan_size to 0;
SET
postgres=# select * from pg_namespace;
ERROR: invalid value for parameter "default_table_access_method": "missing"
DETAIL: Table access method "missing" does not exist.
CONTEXT: while setting parameter "default_table_access_method" to "missing"
parallel worker
OTOH, there is no ERROR on reload or restart.
It is fair to argue that invalid GUC values should be ignored in
certain cases like parallel query but we should have the same solution
for other similar parameters as well.
As for the synchronized_standby_slots, we can follow the behavior
similar to check_synchronous_standby_names and just give parsing
ERRORs. Any non-existent slot related errors can be given when that
parameter is later used.
--
With Regards,
Amit Kapila.
On Tuesday, September 9, 2025 1:30 PM Amit Kapila <amit.kapila16@gmail.com> wrote:
On Mon, Sep 8, 2025 at 2:56 PM Alexander Kukushkin
<cyberdemn@gmail.com> wrote:Recently we also hit this problem.
I think in a current state check_synchronized_standby_slots() and
validate_sync_standby_slots() functions are not very useful:
- When the hook is executed from postmaster it only checks that
synchronized_standby_slots contains a valid list, but doesn't check that
replication slots exists, because MyProc is NULL. It happens both, on start and
on reload.- When executed from other backends set_config_with_handle() is called
with elevel = 0, and therefore elevel becomes DEBUG3, which results in no
useful error/warning messages.There are a couple of places where check_synchronized_standby_slots()
failure is not ignored:
1. alter system set synchronized_standby_slots='invalid value'; 2.
Parallel workers, because RestoreGUCState() callsset_config_option_ext()->set_config_with_handle() with elevel=ERROR. As a
result, parallel workers fail to start with the error.With parallel workers it is actually even worse - we get the error even in case
of standby:
1. start standby with synchronized_standby_slots referring to
non-existing slots 2. SET parallel_setup_cost, parallel_tuple_cost,
and min_parallel_table_scan_size to 0 3. Run select * from pg_namespace;and observe following error:
ERROR: invalid value for parameter "synchronized_standby_slots": "a1,b1"
DETAIL: replication slot "a1" does not exist
CONTEXT: while setting parameter "synchronized_standby_slots" to"a1,b1"
parallel worker
I see the same behaviour for default_table_access_method and
default_tablespace. For example, see failure cases:
postgres=# Alter system set default_table_access_method='missing';
ERROR: invalid value for parameter "default_table_access_method":
"missing"
DETAIL: Table access method "missing" does not exist.postgres=# SET parallel_setup_cost=0;
SET
postgres=# SET parallel_tuple_cost=0;
SET
postgres=# Set min_parallel_table_scan_size to 0; SET postgres=# select *
from pg_namespace;
ERROR: invalid value for parameter "default_table_access_method":
"missing"
DETAIL: Table access method "missing" does not exist.
CONTEXT: while setting parameter "default_table_access_method" to
"missing"
parallel workerOTOH, there is no ERROR on reload or restart.
It is fair to argue that invalid GUC values should be ignored in certain cases like
parallel query but we should have the same solution for other similar
parameters as well.As for the synchronized_standby_slots, we can follow the behavior similar to
check_synchronous_standby_names and just give parsing ERRORs. Any
non-existent slot related errors can be given when that parameter is later used.
I agree. For synchronized_standby_slots, I think it is acceptable to report only
parsing errors, because slots could be dropped even after validating the slot
existence during GUC loading. Additionally, we would report WARNINGs for
non-existent slots during the wait function anyway (e.g., in
StandbySlotsHaveCaughtup()).
Best Regards,
Hou zj
On Tue, Sep 9, 2025 at 2:39 PM Zhijie Hou (Fujitsu)
<houzj.fnst@fujitsu.com> wrote:
I agree. For synchronized_standby_slots, I think it is acceptable to report only
parsing errors, because slots could be dropped even after validating the slot
existence during GUC loading. Additionally, we would report WARNINGs for
non-existent slots during the wait function anyway (e.g., in
StandbySlotsHaveCaughtup()).
+1, to also address the issue I reported upthread.
As I understand it, only the walsender and the slot sync worker actually
use synchronized_standby_slots. But in the current code, all processes check
for slot existence via the GUC check hook, which wastes cycles. The proposed
change would eliminate that overhead.
Regards,
--
Fujii Masao
Hi,
As for the synchronized_standby_slots, we can follow the behavior
similar to check_synchronous_standby_names and just give parsing
ERRORs. Any non-existent slot related errors can be given when that
parameter is later used.--
Please find attached a patch that implements this. I will work on adding a
test for it.
Thank you,
Rahila Syed
Attachments:
0001-Remove-the-validation-from-the-GUC-check-hook.patchapplication/octet-stream; name=0001-Remove-the-validation-from-the-GUC-check-hook.patchDownload
From 157c293e71cdabd2fb36e3e5ea063ffce5788863 Mon Sep 17 00:00:00 2001
From: Rahila Syed <rahilasyed.90@gmail.com>
Date: Wed, 10 Sep 2025 15:07:15 +0530
Subject: [PATCH] Remove the validation from the GUC check hook
The validation in check_synchronized_standby_slots cannot be run
in postmaster and hence can result inconsistent values in some
backends that inherit the value from postmaster and those
that are started newly. Also, this validation results in parallel
workers fail to with error. This causes all the commands run by
parallel workers to fail, which seems unnecesary. This validation
already happens in StandbySlotsHaveCaughtup() where this GUC is
used, so it can be removed from the GUC check.
---
src/backend/replication/slot.c | 36 ----------------------------------
1 file changed, 36 deletions(-)
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index fd0fdb96d42..9daea9ea211 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -2754,42 +2754,6 @@ validate_sync_standby_slots(char *rawname, List **elemlist)
{
GUC_check_errdetail("List syntax is invalid.");
}
- else if (MyProc)
- {
- /*
- * Check that each specified slot exist and is physical.
- *
- * Because we need an LWLock, we cannot do this on processes without a
- * PGPROC, so we skip it there; but see comments in
- * StandbySlotsHaveCaughtup() as to why that's not a problem.
- */
- LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
-
- foreach_ptr(char, name, *elemlist)
- {
- ReplicationSlot *slot;
-
- slot = SearchNamedReplicationSlot(name, false);
-
- if (!slot)
- {
- GUC_check_errdetail("Replication slot \"%s\" does not exist.",
- name);
- ok = false;
- break;
- }
-
- if (!SlotIsPhysical(slot))
- {
- GUC_check_errdetail("\"%s\" is not a physical replication slot.",
- name);
- ok = false;
- break;
- }
- }
-
- LWLockRelease(ReplicationSlotControlLock);
- }
return ok;
}
--
2.34.1
On Wed, Sep 10, 2025 at 3:33 PM Rahila Syed <rahilasyed90@gmail.com> wrote:
Hi,
As for the synchronized_standby_slots, we can follow the behavior
similar to check_synchronous_standby_names and just give parsing
ERRORs. Any non-existent slot related errors can be given when that
parameter is later used.--
Please find attached a patch that implements this. I will work on adding a test for it.
I suggest removing validate_sync_standby_slots() entirely since there
isn’t much left in it.
The below logic currently in validate_sync_standby_slots() to parse
the list of slots can be directly moved into
check_synchronized_standby_slots().
/* Verify syntax and parse string into a list of identifiers */
ok = SplitIdentifierString(rawname, ',', elemlist);
if (!ok)
GUC_check_errdetail("List syntax is invalid.");
--
With Regards,
Ashutosh Sharma.
On Wed, 10 Sept 2025 at 15:33, Rahila Syed <rahilasyed90@gmail.com> wrote:
Hi,
As for the synchronized_standby_slots, we can follow the behavior
similar to check_synchronous_standby_names and just give parsing
ERRORs. Any non-existent slot related errors can be given when that
parameter is later used.--
Please find attached a patch that implements this. I will work on adding a test for it.
Hi Rahila,
I think we should also add a parsing check for slot names specified in
the GUC synchronize_standby_slots as suggested by Amit in [1]/messages/by-id/CAA4eK1Jprqfs_URBmZ5=OOL98D05rPiGup1sscWgcCGcWU=9iA@mail.gmail.com.
I think we should also update the comment message in function
StandbySlotsHaveCaughtup
/*
* If a slot name provided in synchronized_standby_slots does not
* exist, report a message and exit the loop.
*
* Though validate_sync_standby_slots (the GUC check_hook) tries to
* avoid this, it can nonetheless happen because the user can specify
* a nonexistent slot name before server startup. That function cannot
* validate such a slot during startup, as ReplicationSlotCtl is not
* initialized by then. Also, the user might have dropped one slot.
*/
I made the changes in the above for the same and attached the updated patch.
[1]: /messages/by-id/CAA4eK1Jprqfs_URBmZ5=OOL98D05rPiGup1sscWgcCGcWU=9iA@mail.gmail.com
Thanks,
Shlok Kyal
Attachments:
v2-0001-Remove-the-validation-from-the-GUC-check-hook-and.patchapplication/octet-stream; name=v2-0001-Remove-the-validation-from-the-GUC-check-hook-and.patchDownload
From 779584f273359ae5c4b80e872a493c0cca41a053 Mon Sep 17 00:00:00 2001
From: Shlok Kyal <shlok.kyal.oss@gmail.com>
Date: Wed, 10 Sep 2025 15:08:23 +0530
Subject: [PATCH v2] Remove the validation from the GUC check hook and add
parsing check
The validation in check_synchronized_standby_slots cannot be run
in postmaster and hence can result inconsistent values in some
backends that inherit the value from postmaster and those
that are started newly. Also, this validation results in parallel
workers fail to with error. This causes all the commands run by
parallel workers to fail, which seems unnecesary. This validation
already happens in StandbySlotsHaveCaughtup() where this GUC is
used, so it can be removed from the GUC check. Also added a
parsing check for the slot names specified in this GUC.
---
src/backend/replication/slot.c | 35 ++--------------------------------
1 file changed, 2 insertions(+), 33 deletions(-)
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index fd0fdb96d42..ee5d320d0aa 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -2754,41 +2754,16 @@ validate_sync_standby_slots(char *rawname, List **elemlist)
{
GUC_check_errdetail("List syntax is invalid.");
}
- else if (MyProc)
+ else
{
- /*
- * Check that each specified slot exist and is physical.
- *
- * Because we need an LWLock, we cannot do this on processes without a
- * PGPROC, so we skip it there; but see comments in
- * StandbySlotsHaveCaughtup() as to why that's not a problem.
- */
- LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
-
foreach_ptr(char, name, *elemlist)
{
- ReplicationSlot *slot;
-
- slot = SearchNamedReplicationSlot(name, false);
-
- if (!slot)
+ if (!ReplicationSlotValidateName(name, false, ERROR))
{
- GUC_check_errdetail("Replication slot \"%s\" does not exist.",
- name);
- ok = false;
- break;
- }
-
- if (!SlotIsPhysical(slot))
- {
- GUC_check_errdetail("\"%s\" is not a physical replication slot.",
- name);
ok = false;
break;
}
}
-
- LWLockRelease(ReplicationSlotControlLock);
}
return ok;
@@ -2949,12 +2924,6 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
/*
* If a slot name provided in synchronized_standby_slots does not
* exist, report a message and exit the loop.
- *
- * Though validate_sync_standby_slots (the GUC check_hook) tries to
- * avoid this, it can nonetheless happen because the user can specify
- * a nonexistent slot name before server startup. That function cannot
- * validate such a slot during startup, as ReplicationSlotCtl is not
- * initialized by then. Also, the user might have dropped one slot.
*/
if (!slot)
{
--
2.34.1
Hi,
On Wed, 10 Sept 2025 at 13:34, Shlok Kyal <shlok.kyal.oss@gmail.com> wrote:
I think we should also add a parsing check for slot names specified in
the GUC synchronize_standby_slots as suggested by Amit in [1].
I made the changes in the above for the same and attached the updated
patch.
I agree, validating that list contains valid replication slot names is a
good idea.
However, you used ReplicationSlotValidateName() function, which is not a
good fit for it, especially when it is called with elevel=ERROR in
postmaster.
--
Regards,
--
Alexander Kukushkin
On Wed, Sep 10, 2025 at 5:23 PM Alexander Kukushkin <cyberdemn@gmail.com> wrote:
On Wed, 10 Sept 2025 at 13:34, Shlok Kyal <shlok.kyal.oss@gmail.com> wrote:
I think we should also add a parsing check for slot names specified in
the GUC synchronize_standby_slots as suggested by Amit in [1].
I made the changes in the above for the same and attached the updated patch.I agree, validating that list contains valid replication slot names is a good idea.
However, you used ReplicationSlotValidateName() function, which is not a good fit for it, especially when it is called with elevel=ERROR in postmaster.
Can you please explain why you think so? And what is your proposal for the same?
BTW, we should also try to conclude on my yesterday's point as to why
it is okay to have the same behavior for default_tablespace and
default_table_access_method and not for this parameter? I am asking
because if we change the current behavior, tomorrow, we can get
complaints that one expects the old behaviour as that was similar to
other GUCs like default_tablespace and default_table_access_method.
--
With Regards,
Amit Kapila.
On Thu, Sep 11, 2025 at 9:02 AM Amit Kapila <amit.kapila16@gmail.com> wrote:
On Wed, Sep 10, 2025 at 5:23 PM Alexander Kukushkin <cyberdemn@gmail.com> wrote:
On Wed, 10 Sept 2025 at 13:34, Shlok Kyal <shlok.kyal.oss@gmail.com> wrote:
I think we should also add a parsing check for slot names specified in
the GUC synchronize_standby_slots as suggested by Amit in [1].
I made the changes in the above for the same and attached the updated patch.I agree, validating that list contains valid replication slot names is a good idea.
However, you used ReplicationSlotValidateName() function, which is not a good fit for it, especially when it is called with elevel=ERROR in postmaster.Can you please explain why you think so? And what is your proposal for the same?
You are right and I think we should use WARNING here as is used in
check_primary_slot_name() for the same function call. For ERROR
reporting, we need to use GUC_check_* functions. Also, probably the
ERROR during startup could lead to shutdown.
--
With Regards,
Amit Kapila.
On Thu, 11 Sept 2025 at 09:20, Amit Kapila <amit.kapila16@gmail.com> wrote:
On Thu, Sep 11, 2025 at 9:02 AM Amit Kapila <amit.kapila16@gmail.com> wrote:
On Wed, Sep 10, 2025 at 5:23 PM Alexander Kukushkin <cyberdemn@gmail.com> wrote:
On Wed, 10 Sept 2025 at 13:34, Shlok Kyal <shlok.kyal.oss@gmail.com> wrote:
I think we should also add a parsing check for slot names specified in
the GUC synchronize_standby_slots as suggested by Amit in [1].
I made the changes in the above for the same and attached the updated patch.I agree, validating that list contains valid replication slot names is a good idea.
However, you used ReplicationSlotValidateName() function, which is not a good fit for it, especially when it is called with elevel=ERROR in postmaster.Can you please explain why you think so? And what is your proposal for the same?
You are right and I think we should use WARNING here as is used in
check_primary_slot_name() for the same function call. For ERROR
reporting, we need to use GUC_check_* functions. Also, probably the
ERROR during startup could lead to shutdown.
I tested by setting elevel=ERROR and elevel=WARNING in the function
ReplicationSlotValidateName.
For elevel=ERROR,
After hitting ereport inside function ReplicationSlotValidateName, the
PG_CATCH() in 'call_string_check_hook' and process is terminated.
Server logs are
2025-09-11 10:01:17.909 IST [1995206] FATAL: replication slot name
"myslot1*" contains invalid character
2025-09-11 10:01:17.909 IST [1995206] HINT: Replication slot names
may only contain lower case letters, numbers, and the underscore
character.
For level=WARNING,
Even after hitting the ereport, it is continuing with the normal flow of code.
Server logs are:
2025-09-11 10:27:30.195 IST [2013341] WARNING: replication slot name
"myslot1*" contains invalid character
2025-09-11 10:27:30.195 IST [2013341] HINT: Replication slot names
may only contain lower case letters, numbers, and the underscore
character.
2025-09-11 10:28:13.863 IST [2013341] LOG: invalid value for
parameter "synchronized_standby_slots": "myslot1*"
2025-09-11 10:28:13.863 IST [2013341] FATAL: configuration file
"/home/ubuntu/Project/inst/pg_11_9_tmp_4/bin/primary/postgresql.conf"
contains errors
I think we can use ReplicationSlotValidateName with elevel=WARNING here.
I have attached an updated patch with this change.
Thanks,
Shlok Kyal
Attachments:
v3-0001-Remove-the-validation-from-the-GUC-check-hook-and.patchapplication/octet-stream; name=v3-0001-Remove-the-validation-from-the-GUC-check-hook-and.patchDownload
From 5733963f161f9ae2413a4b87963a428fac2900a2 Mon Sep 17 00:00:00 2001
From: Shlok Kyal <shlok.kyal.oss@gmail.com>
Date: Wed, 10 Sep 2025 15:08:23 +0530
Subject: [PATCH v3] Remove the validation from the GUC check hook and add
parsing check
The validation in check_synchronized_standby_slots cannot be run
in postmaster and hence can result inconsistent values in some
backends that inherit the value from postmaster and those
that are started newly. Also, this validation results in parallel
workers fail to with error. This causes all the commands run by
parallel workers to fail, which seems unnecesary. This validation
already happens in StandbySlotsHaveCaughtup() where this GUC is
used, so it can be removed from the GUC check. Also added a
parsing check for the slot names specified in this GUC.
---
src/backend/replication/slot.c | 35 ++--------------------------------
1 file changed, 2 insertions(+), 33 deletions(-)
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index fd0fdb96d42..699090daa38 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -2754,41 +2754,16 @@ validate_sync_standby_slots(char *rawname, List **elemlist)
{
GUC_check_errdetail("List syntax is invalid.");
}
- else if (MyProc)
+ else
{
- /*
- * Check that each specified slot exist and is physical.
- *
- * Because we need an LWLock, we cannot do this on processes without a
- * PGPROC, so we skip it there; but see comments in
- * StandbySlotsHaveCaughtup() as to why that's not a problem.
- */
- LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
-
foreach_ptr(char, name, *elemlist)
{
- ReplicationSlot *slot;
-
- slot = SearchNamedReplicationSlot(name, false);
-
- if (!slot)
+ if (!ReplicationSlotValidateName(name, false, WARNING))
{
- GUC_check_errdetail("Replication slot \"%s\" does not exist.",
- name);
- ok = false;
- break;
- }
-
- if (!SlotIsPhysical(slot))
- {
- GUC_check_errdetail("\"%s\" is not a physical replication slot.",
- name);
ok = false;
break;
}
}
-
- LWLockRelease(ReplicationSlotControlLock);
}
return ok;
@@ -2949,12 +2924,6 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
/*
* If a slot name provided in synchronized_standby_slots does not
* exist, report a message and exit the loop.
- *
- * Though validate_sync_standby_slots (the GUC check_hook) tries to
- * avoid this, it can nonetheless happen because the user can specify
- * a nonexistent slot name before server startup. That function cannot
- * validate such a slot during startup, as ReplicationSlotCtl is not
- * initialized by then. Also, the user might have dropped one slot.
*/
if (!slot)
{
--
2.34.1
On Thu, Sep 11, 2025 at 11:00 AM Shlok Kyal <shlok.kyal.oss@gmail.com>
wrote:
On Thu, 11 Sept 2025 at 09:20, Amit Kapila <amit.kapila16@gmail.com>
wrote:
On Thu, Sep 11, 2025 at 9:02 AM Amit Kapila <amit.kapila16@gmail.com>
wrote:
On Wed, Sep 10, 2025 at 5:23 PM Alexander Kukushkin <
cyberdemn@gmail.com> wrote:
On Wed, 10 Sept 2025 at 13:34, Shlok Kyal <shlok.kyal.oss@gmail.com>
wrote:
I think we should also add a parsing check for slot names
specified in
the GUC synchronize_standby_slots as suggested by Amit in [1].
I made the changes in the above for the same and attached the
updated patch.
I agree, validating that list contains valid replication slot names
is a good idea.
However, you used ReplicationSlotValidateName() function, which is
not a good fit for it, especially when it is called with elevel=ERROR in
postmaster.
Can you please explain why you think so? And what is your proposal
for the same?
You are right and I think we should use WARNING here as is used in
check_primary_slot_name() for the same function call. For ERROR
reporting, we need to use GUC_check_* functions. Also, probably the
ERROR during startup could lead to shutdown.I tested by setting elevel=ERROR and elevel=WARNING in the function
ReplicationSlotValidateName.For elevel=ERROR,
After hitting ereport inside function ReplicationSlotValidateName, the
PG_CATCH() in 'call_string_check_hook' and process is terminated.
Server logs are
2025-09-11 10:01:17.909 IST [1995206] FATAL: replication slot name
"myslot1*" contains invalid character
2025-09-11 10:01:17.909 IST [1995206] HINT: Replication slot names
may only contain lower case letters, numbers, and the underscore
character.For level=WARNING,
Even after hitting the ereport, it is continuing with the normal flow of
code.
Server logs are:
2025-09-11 10:27:30.195 IST [2013341] WARNING: replication slot name
"myslot1*" contains invalid character
2025-09-11 10:27:30.195 IST [2013341] HINT: Replication slot names
may only contain lower case letters, numbers, and the underscore
character.
2025-09-11 10:28:13.863 IST [2013341] LOG: invalid value for
parameter "synchronized_standby_slots": "myslot1*"
2025-09-11 10:28:13.863 IST [2013341] FATAL: configuration file
"/home/ubuntu/Project/inst/pg_11_9_tmp_4/bin/primary/postgresql.conf"
contains errorsI think we can use ReplicationSlotValidateName with elevel=WARNING here.
I have attached an updated patch with this change.
I would suggest getting rid of the "*ok*" flag, it’s probably not needed.
I’d rather rewrite validate_sync_standby_slots() like this:
static bool
validate_sync_standby_slots(char *rawname, List **elemlist)
{
/* Verify syntax and parse string into a list of identifiers */
if (!SplitIdentifierString(rawname, ',', elemlist))
GUC_check_errdetail("List syntax is invalid.");
else
{
foreach_ptr(char, name, *elemlist)
{
if (!ReplicationSlotValidateName(name, false, WARNING))
return false;
}
}
return true;
}
--
With Regards,
Ashutosh Sharma.
On Thu, Sep 11, 2025 at 11:07 AM Ashutosh Sharma <ashu.coek88@gmail.com>
wrote:
On Thu, Sep 11, 2025 at 11:00 AM Shlok Kyal <shlok.kyal.oss@gmail.com>
wrote:On Thu, 11 Sept 2025 at 09:20, Amit Kapila <amit.kapila16@gmail.com>
wrote:
On Thu, Sep 11, 2025 at 9:02 AM Amit Kapila <amit.kapila16@gmail.com>
wrote:
On Wed, Sep 10, 2025 at 5:23 PM Alexander Kukushkin <
cyberdemn@gmail.com> wrote:
On Wed, 10 Sept 2025 at 13:34, Shlok Kyal <
shlok.kyal.oss@gmail.com> wrote:
I think we should also add a parsing check for slot names
specified in
the GUC synchronize_standby_slots as suggested by Amit in [1].
I made the changes in the above for the same and attached theupdated patch.
I agree, validating that list contains valid replication slot
names is a good idea.
However, you used ReplicationSlotValidateName() function, which is
not a good fit for it, especially when it is called with elevel=ERROR in
postmaster.Can you please explain why you think so? And what is your proposal
for the same?
You are right and I think we should use WARNING here as is used in
check_primary_slot_name() for the same function call. For ERROR
reporting, we need to use GUC_check_* functions. Also, probably the
ERROR during startup could lead to shutdown.I tested by setting elevel=ERROR and elevel=WARNING in the function
ReplicationSlotValidateName.For elevel=ERROR,
After hitting ereport inside function ReplicationSlotValidateName, the
PG_CATCH() in 'call_string_check_hook' and process is terminated.
Server logs are
2025-09-11 10:01:17.909 IST [1995206] FATAL: replication slot name
"myslot1*" contains invalid character
2025-09-11 10:01:17.909 IST [1995206] HINT: Replication slot names
may only contain lower case letters, numbers, and the underscore
character.For level=WARNING,
Even after hitting the ereport, it is continuing with the normal flow ofcode.
Server logs are:
2025-09-11 10:27:30.195 IST [2013341] WARNING: replication slot name
"myslot1*" contains invalid character
2025-09-11 10:27:30.195 IST [2013341] HINT: Replication slot names
may only contain lower case letters, numbers, and the underscore
character.
2025-09-11 10:28:13.863 IST [2013341] LOG: invalid value for
parameter "synchronized_standby_slots": "myslot1*"
2025-09-11 10:28:13.863 IST [2013341] FATAL: configuration file
"/home/ubuntu/Project/inst/pg_11_9_tmp_4/bin/primary/postgresql.conf"
contains errorsI think we can use ReplicationSlotValidateName with elevel=WARNING here.
I have attached an updated patch with this change.I would suggest getting rid of the "*ok*" flag, it’s probably not needed.
I’d rather rewrite validate_sync_standby_slots() like this:static bool
validate_sync_standby_slots(char *rawname, List **elemlist)
{
/* Verify syntax and parse string into a list of identifiers */
if (!SplitIdentifierString(rawname, ',', elemlist))
GUC_check_errdetail("List syntax is invalid.");
else
{
foreach_ptr(char, name, *elemlist)
{
if (!ReplicationSlotValidateName(name, false, WARNING))
return false;
}
}return true;
}
Apart from this change, if you agree, then you may also add a test-case
that sets synchronized_standby_slots to some reserved name like
"pg_conflict_detection" to verify for the WARNING message.
--
With Regards,
Ashutosh Sharma.
Hi,
BTW, we should also try to conclude on my yesterday's point as to why
it is okay to have the same behavior for default_tablespace and
default_table_access_method and not for this parameter? I am asking
because if we change the current behavior, tomorrow, we can get
complaints that one expects the old behaviour as that was similar to
other GUCs like default_tablespace and default_table_access_method.
Fair point. I haven't examined the validation of GUCs in parallel workers
closely,
but one argument for preventing parallel workers from failing due to an
incorrect
value of synchronized_standby_slots is that a select query works in this
situation
without parallel workers.
Whereas, for incorrect values of default_tablespace and
default_table_access_method,
most commands would fail regardless of whether parallel workers are enabled.
PFA a test for the original bug report on this thread. This applies on the
v3 version of the patch
that was shared.
Thank you,
Rahila Syed
Attachments:
0001-Add-a-test-for-a-disabled-GUC-check-for-parallel-wor.patchapplication/octet-stream; name=0001-Add-a-test-for-a-disabled-GUC-check-for-parallel-wor.patchDownload
From 9fe0d712b3d5260b6ef39d5d3afca575b08514e1 Mon Sep 17 00:00:00 2001
From: Rahila Syed <rahilasyed.90@gmail.com>
Date: Thu, 11 Sep 2025 11:56:21 +0530
Subject: [PATCH] Add a test for a disabled GUC check for parallel workers
---
.../modules/test_misc/t/009_guc_validation.pl | 29 +++++++++++++++++++
1 file changed, 29 insertions(+)
create mode 100644 src/test/modules/test_misc/t/009_guc_validation.pl
diff --git a/src/test/modules/test_misc/t/009_guc_validation.pl b/src/test/modules/test_misc/t/009_guc_validation.pl
new file mode 100644
index 00000000000..6d7421e414a
--- /dev/null
+++ b/src/test/modules/test_misc/t/009_guc_validation.pl
@@ -0,0 +1,29 @@
+
+# Copyright (c) 2024-2025, PostgreSQL Global Development Group
+
+# Tests to cross-check the consistency of GUC parameters with
+# postgresql.conf.sample.
+
+use strict;
+use warnings FATAL => 'all';
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+my $psql_err;
+my $node = PostgreSQL::Test::Cluster->new('main');
+$node->init;
+$node->append_conf('postgresql.conf', "synchronized_standby_slots = missing");
+# Node starts with invalid synchronized_standby_slots
+$node->start;
+
+# Should not throw an error when parallel worker starts up.
+
+my $parallel_worker_scan = $node->psql(
+ 'postgres', qq( SET min_parallel_table_scan_size TO 0; SET parallel_setup_cost TO 0;
+ SET parallel_tuple_cost TO 0;
+ SELECT * from pg_namespace;), stderr => \$psql_err);
+
+like ( $psql_err,
+ qr//);
+done_testing();
--
2.34.1
On Thu, 11 Sept 2025 at 12:00, Rahila Syed <rahilasyed90@gmail.com> wrote:
Hi,
BTW, we should also try to conclude on my yesterday's point as to why
it is okay to have the same behavior for default_tablespace and
default_table_access_method and not for this parameter? I am asking
because if we change the current behavior, tomorrow, we can get
complaints that one expects the old behaviour as that was similar to
other GUCs like default_tablespace and default_table_access_method.Fair point. I haven't examined the validation of GUCs in parallel workers closely,
but one argument for preventing parallel workers from failing due to an incorrect
value of synchronized_standby_slots is that a select query works in this situation
without parallel workers.Whereas, for incorrect values of default_tablespace and default_table_access_method,
most commands would fail regardless of whether parallel workers are enabled.PFA a test for the original bug report on this thread. This applies on the v3 version of the patch
that was shared.
Thanks for sharing the patch. I checked the test and it looks good to
me. But I am not sure if we should have a new file for the test. I
have added the test in the '040_standby_failover_slots_sync.pl' file
along with some other tests.
Also I have addressed the comments by Ashutosh in [1]/messages/by-id/CAE9k0P=x3J3nmSmYKmTkiFXTDKLxJkXFO4+VHJyNu01Od6CZfg@mail.gmail.com[2]/messages/by-id/CAE9k0P=OFMFCRy9aDGWZ3bt91tbB1WnzsAbzXN72iWBaGVuMrw@mail.gmail.com.
I have attached the updated v4 patch
[1]: /messages/by-id/CAE9k0P=x3J3nmSmYKmTkiFXTDKLxJkXFO4+VHJyNu01Od6CZfg@mail.gmail.com
[2]: /messages/by-id/CAE9k0P=OFMFCRy9aDGWZ3bt91tbB1WnzsAbzXN72iWBaGVuMrw@mail.gmail.com
Thanks,
Shlok Kyal
Attachments:
v4-0001-Remove-the-validation-from-the-GUC-check-hook-and.patchapplication/octet-stream; name=v4-0001-Remove-the-validation-from-the-GUC-check-hook-and.patchDownload
From 6b11c3146d12f8ce3701d648e3dde0a8d94e4fd8 Mon Sep 17 00:00:00 2001
From: Shlok Kyal <shlok.kyal.oss@gmail.com>
Date: Wed, 10 Sep 2025 15:08:23 +0530
Subject: [PATCH v4] Remove the validation from the GUC check hook and add
parsing check
The validation in check_synchronized_standby_slots cannot be run
in postmaster and hence can result inconsistent values in some
backends that inherit the value from postmaster and those
that are started newly. Also, this validation results in parallel
workers fail to with error. This causes all the commands run by
parallel workers to fail, which seems unnecesary. This validation
already happens in StandbySlotsHaveCaughtup() where this GUC is
used, so it can be removed from the GUC check. Also added a
parsing check for the slot names specified in this GUC.
---
src/backend/replication/slot.c | 53 +++----------------
.../t/040_standby_failover_slots_sync.pl | 34 ++++++++++++
2 files changed, 41 insertions(+), 46 deletions(-)
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index fd0fdb96d42..f3f2fc8b8fc 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -2745,53 +2745,20 @@ GetSlotInvalidationCauseName(ReplicationSlotInvalidationCause cause)
static bool
validate_sync_standby_slots(char *rawname, List **elemlist)
{
- bool ok;
-
/* Verify syntax and parse string into a list of identifiers */
- ok = SplitIdentifierString(rawname, ',', elemlist);
-
- if (!ok)
+ if (!SplitIdentifierString(rawname, ',', elemlist))
{
GUC_check_errdetail("List syntax is invalid.");
+ return false;
}
- else if (MyProc)
- {
- /*
- * Check that each specified slot exist and is physical.
- *
- * Because we need an LWLock, we cannot do this on processes without a
- * PGPROC, so we skip it there; but see comments in
- * StandbySlotsHaveCaughtup() as to why that's not a problem.
- */
- LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
-
- foreach_ptr(char, name, *elemlist)
- {
- ReplicationSlot *slot;
-
- slot = SearchNamedReplicationSlot(name, false);
-
- if (!slot)
- {
- GUC_check_errdetail("Replication slot \"%s\" does not exist.",
- name);
- ok = false;
- break;
- }
- if (!SlotIsPhysical(slot))
- {
- GUC_check_errdetail("\"%s\" is not a physical replication slot.",
- name);
- ok = false;
- break;
- }
- }
-
- LWLockRelease(ReplicationSlotControlLock);
+ foreach_ptr(char, name, *elemlist)
+ {
+ if (!ReplicationSlotValidateName(name, false, WARNING))
+ return false;
}
- return ok;
+ return true;
}
/*
@@ -2949,12 +2916,6 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
/*
* If a slot name provided in synchronized_standby_slots does not
* exist, report a message and exit the loop.
- *
- * Though validate_sync_standby_slots (the GUC check_hook) tries to
- * avoid this, it can nonetheless happen because the user can specify
- * a nonexistent slot name before server startup. That function cannot
- * validate such a slot during startup, as ReplicationSlotCtl is not
- * initialized by then. Also, the user might have dropped one slot.
*/
if (!slot)
{
diff --git a/src/test/recovery/t/040_standby_failover_slots_sync.pl b/src/test/recovery/t/040_standby_failover_slots_sync.pl
index 2c61c51e914..ae2119a186d 100644
--- a/src/test/recovery/t/040_standby_failover_slots_sync.pl
+++ b/src/test/recovery/t/040_standby_failover_slots_sync.pl
@@ -966,4 +966,38 @@ $result = $standby1->safe_psql('postgres',
is($result, '1', "data can be consumed using snap_test_slot");
+##################################################
+# Test for GUC synchronized standby slots
+##################################################
+
+# Cannot be set synchronized_standby_slots to a reserved slot name
+($result, $stdout, $stderr) = $primary->psql('postgres',
+ "ALTER SYSTEM SET synchronized_standby_slots='pg_conflict_detection'");
+ok( $stderr =~
+ m/WARNING: replication slot name "pg_conflict_detection" is reserved/,
+ "Cannot use a reserverd slot name");
+
+# Cannot be set synchronized_standby_slots to slot name with invalid characters
+($result, $stdout, $stderr) = $primary->psql('postgres',
+ "ALTER SYSTEM SET synchronized_standby_slots='invalid*'");
+ok( $stderr =~
+ m/WARNING: replication slot name "invalid\*" contains invalid character/,
+ "Cannot use a invalid slot name");
+
+# Can set synchronized_standby_slots to a non-existent slot name
+$primary->safe_psql(
+ 'postgres', qq[
+ ALTER SYSTEM SET synchronized_standby_slots='missing';
+ SELECT pg_reload_conf();
+]);
+
+# Parallel worker does not throw error during startup.
+$primary->safe_psql(
+ 'postgres', qq[
+ SET min_parallel_table_scan_size TO 0;
+ SET parallel_setup_cost TO 0;
+ SET parallel_tuple_cost TO 0;
+ SELECT * from pg_namespace;
+]);
+
done_testing();
--
2.34.1
On Fri, Sep 12, 2025 at 2:34 PM Shlok Kyal <shlok.kyal.oss@gmail.com> wrote:
I have attached the updated v4 patch
+# Cannot be set synchronized_standby_slots to a reserved slot name
+($result, $stdout, $stderr) = $primary->psql('postgres',
+ "ALTER SYSTEM SET synchronized_standby_slots='pg_conflict_detection'");
+ok( $stderr =~
+ m/WARNING: replication slot name "pg_conflict_detection" is reserved/,
+ "Cannot use a reserverd slot name");
+
+# Cannot be set synchronized_standby_slots to slot name with invalid characters
+($result, $stdout, $stderr) = $primary->psql('postgres',
+ "ALTER SYSTEM SET synchronized_standby_slots='invalid*'");
+ok( $stderr =~
+ m/WARNING: replication slot name "invalid\*" contains invalid character/,
+ "Cannot use a invalid slot name");
These tests can be present in some sql file. I think you have kept
these in the .pl file to keep it along with other tests but I think
these are better suited for some .sql file.
--
With Regards,
Amit Kapila.
On Tue, 23 Sept 2025 at 09:55, Amit Kapila <amit.kapila16@gmail.com> wrote:
On Fri, Sep 12, 2025 at 2:34 PM Shlok Kyal <shlok.kyal.oss@gmail.com> wrote:
I have attached the updated v4 patch
+# Cannot be set synchronized_standby_slots to a reserved slot name +($result, $stdout, $stderr) = $primary->psql('postgres', + "ALTER SYSTEM SET synchronized_standby_slots='pg_conflict_detection'"); +ok( $stderr =~ + m/WARNING: replication slot name "pg_conflict_detection" is reserved/, + "Cannot use a reserverd slot name"); + +# Cannot be set synchronized_standby_slots to slot name with invalid characters +($result, $stdout, $stderr) = $primary->psql('postgres', + "ALTER SYSTEM SET synchronized_standby_slots='invalid*'"); +ok( $stderr =~ + m/WARNING: replication slot name "invalid\*" contains invalid character/, + "Cannot use a invalid slot name");These tests can be present in some sql file. I think you have kept
these in the .pl file to keep it along with other tests but I think
these are better suited for some .sql file.
Thanks for reviewing the patch.
I have moved the tests to the guc.sql file. I have attached the updated patch.
Thanks,
Shlok Kyal
Attachments:
v5-0001-Remove-the-validation-from-the-GUC-check-hook-and.patchapplication/octet-stream; name=v5-0001-Remove-the-validation-from-the-GUC-check-hook-and.patchDownload
From a01804aa1c46639cd68a9daa06672ec84a00e063 Mon Sep 17 00:00:00 2001
From: Shlok Kyal <shlok.kyal.oss@gmail.com>
Date: Wed, 10 Sep 2025 15:08:23 +0530
Subject: [PATCH v5] Remove the validation from the GUC check hook and add
parsing check
The validation in check_synchronized_standby_slots cannot be run
in postmaster and hence can result inconsistent values in some
backends that inherit the value from postmaster and those
that are started newly. Also, this validation results in parallel
workers fail to with error. This causes all the commands run by
parallel workers to fail, which seems unnecesary. This validation
already happens in StandbySlotsHaveCaughtup() where this GUC is
used, so it can be removed from the GUC check. Also added a
parsing check for the slot names specified in this GUC.
---
src/backend/replication/slot.c | 53 ++++---------------------------
src/test/regress/expected/guc.out | 31 ++++++++++++++++++
src/test/regress/sql/guc.sql | 19 +++++++++++
3 files changed, 57 insertions(+), 46 deletions(-)
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index fd0fdb96d42..f3f2fc8b8fc 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -2745,53 +2745,20 @@ GetSlotInvalidationCauseName(ReplicationSlotInvalidationCause cause)
static bool
validate_sync_standby_slots(char *rawname, List **elemlist)
{
- bool ok;
-
/* Verify syntax and parse string into a list of identifiers */
- ok = SplitIdentifierString(rawname, ',', elemlist);
-
- if (!ok)
+ if (!SplitIdentifierString(rawname, ',', elemlist))
{
GUC_check_errdetail("List syntax is invalid.");
+ return false;
}
- else if (MyProc)
- {
- /*
- * Check that each specified slot exist and is physical.
- *
- * Because we need an LWLock, we cannot do this on processes without a
- * PGPROC, so we skip it there; but see comments in
- * StandbySlotsHaveCaughtup() as to why that's not a problem.
- */
- LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
-
- foreach_ptr(char, name, *elemlist)
- {
- ReplicationSlot *slot;
-
- slot = SearchNamedReplicationSlot(name, false);
-
- if (!slot)
- {
- GUC_check_errdetail("Replication slot \"%s\" does not exist.",
- name);
- ok = false;
- break;
- }
- if (!SlotIsPhysical(slot))
- {
- GUC_check_errdetail("\"%s\" is not a physical replication slot.",
- name);
- ok = false;
- break;
- }
- }
-
- LWLockRelease(ReplicationSlotControlLock);
+ foreach_ptr(char, name, *elemlist)
+ {
+ if (!ReplicationSlotValidateName(name, false, WARNING))
+ return false;
}
- return ok;
+ return true;
}
/*
@@ -2949,12 +2916,6 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
/*
* If a slot name provided in synchronized_standby_slots does not
* exist, report a message and exit the loop.
- *
- * Though validate_sync_standby_slots (the GUC check_hook) tries to
- * avoid this, it can nonetheless happen because the user can specify
- * a nonexistent slot name before server startup. That function cannot
- * validate such a slot during startup, as ReplicationSlotCtl is not
- * initialized by then. Also, the user might have dropped one slot.
*/
if (!slot)
{
diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out
index 7f9e29c765c..436acc8da64 100644
--- a/src/test/regress/expected/guc.out
+++ b/src/test/regress/expected/guc.out
@@ -913,3 +913,34 @@ SELECT name FROM tab_settings_flags
(0 rows)
DROP TABLE tab_settings_flags;
+-- Test for GUC synchronized standby slots
+-- Cannot set synchronized_standby_slots to a reserved slot name.
+ALTER SYSTEM SET synchronized_standby_slots='pg_conflict_detection';
+WARNING: replication slot name "pg_conflict_detection" is reserved
+DETAIL: The name "pg_conflict_detection" is reserved for the conflict detection slot.
+ERROR: invalid value for parameter "synchronized_standby_slots": "pg_conflict_detection"
+-- Cannot set synchronized_standby_slots to a invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+WARNING: replication slot name "invalid*" contains invalid character
+HINT: Replication slot names may only contain lower case letters, numbers, and the underscore character.
+ERROR: invalid value for parameter "synchronized_standby_slots": "invalid*"
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+SELECT pg_reload_conf();
+ pg_reload_conf
+----------------
+ t
+(1 row)
+
+-- Parallel worker does not throw error during startup.
+SET min_parallel_table_scan_size TO 0;
+SET parallel_setup_cost TO 0;
+SET parallel_tuple_cost TO 0;
+CREATE TABLE t1(a int);
+INSERT INTO t1 VALUES(1), (2), (3), (4);
+SELECT count(*) FROM t1;
+ count
+-------
+ 4
+(1 row)
+
diff --git a/src/test/regress/sql/guc.sql b/src/test/regress/sql/guc.sql
index f65f84a2632..3e8e7d5c63a 100644
--- a/src/test/regress/sql/guc.sql
+++ b/src/test/regress/sql/guc.sql
@@ -368,3 +368,22 @@ SELECT name FROM tab_settings_flags
WHERE no_reset AND NOT no_reset_all
ORDER BY 1;
DROP TABLE tab_settings_flags;
+
+-- Test for GUC synchronized standby slots
+-- Cannot set synchronized_standby_slots to a reserved slot name.
+ALTER SYSTEM SET synchronized_standby_slots='pg_conflict_detection';
+
+-- Cannot set synchronized_standby_slots to a invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+SELECT pg_reload_conf();
+
+-- Parallel worker does not throw error during startup.
+SET min_parallel_table_scan_size TO 0;
+SET parallel_setup_cost TO 0;
+SET parallel_tuple_cost TO 0;
+CREATE TABLE t1(a int);
+INSERT INTO t1 VALUES(1), (2), (3), (4);
+SELECT count(*) FROM t1;
--
2.34.1
Hi Amit,
On Tue, Sep 23, 2025 at 1:00 PM Shlok Kyal <shlok.kyal.oss@gmail.com> wrote:
On Tue, 23 Sept 2025 at 09:55, Amit Kapila <amit.kapila16@gmail.com> wrote:
On Fri, Sep 12, 2025 at 2:34 PM Shlok Kyal <shlok.kyal.oss@gmail.com> wrote:
I have attached the updated v4 patch
+# Cannot be set synchronized_standby_slots to a reserved slot name +($result, $stdout, $stderr) = $primary->psql('postgres', + "ALTER SYSTEM SET synchronized_standby_slots='pg_conflict_detection'"); +ok( $stderr =~ + m/WARNING: replication slot name "pg_conflict_detection" is reserved/, + "Cannot use a reserverd slot name"); + +# Cannot be set synchronized_standby_slots to slot name with invalid characters +($result, $stdout, $stderr) = $primary->psql('postgres', + "ALTER SYSTEM SET synchronized_standby_slots='invalid*'"); +ok( $stderr =~ + m/WARNING: replication slot name "invalid\*" contains invalid character/, + "Cannot use a invalid slot name");These tests can be present in some sql file. I think you have kept
these in the .pl file to keep it along with other tests but I think
these are better suited for some .sql file.Thanks for reviewing the patch.
I have moved the tests to the guc.sql file. I have attached the updated patch.
Are we planning to wait for [1]/messages/by-id/CAHGQGwFud-cvthCTfusBfKHBS6Jj6kdAPTdLWKvP2qjUX6L_wA@mail.gmail.com to go in first, since this also
depends on ReplicationSlotValidateName?
[1]: /messages/by-id/CAHGQGwFud-cvthCTfusBfKHBS6Jj6kdAPTdLWKvP2qjUX6L_wA@mail.gmail.com
--
With Regards,
Ashutosh Sharma.
On Wed, Sep 24, 2025 at 12:14 PM Ashutosh Sharma <ashu.coek88@gmail.com> wrote:
Hi Amit,
On Tue, Sep 23, 2025 at 1:00 PM Shlok Kyal <shlok.kyal.oss@gmail.com> wrote:
On Tue, 23 Sept 2025 at 09:55, Amit Kapila <amit.kapila16@gmail.com> wrote:
On Fri, Sep 12, 2025 at 2:34 PM Shlok Kyal <shlok.kyal.oss@gmail.com> wrote:
I have attached the updated v4 patch
+# Cannot be set synchronized_standby_slots to a reserved slot name +($result, $stdout, $stderr) = $primary->psql('postgres', + "ALTER SYSTEM SET synchronized_standby_slots='pg_conflict_detection'"); +ok( $stderr =~ + m/WARNING: replication slot name "pg_conflict_detection" is reserved/, + "Cannot use a reserverd slot name"); + +# Cannot be set synchronized_standby_slots to slot name with invalid characters +($result, $stdout, $stderr) = $primary->psql('postgres', + "ALTER SYSTEM SET synchronized_standby_slots='invalid*'"); +ok( $stderr =~ + m/WARNING: replication slot name "invalid\*" contains invalid character/, + "Cannot use a invalid slot name");These tests can be present in some sql file. I think you have kept
these in the .pl file to keep it along with other tests but I think
these are better suited for some .sql file.Thanks for reviewing the patch.
I have moved the tests to the guc.sql file. I have attached the updated patch.Are we planning to wait for [1] to go in first, since this also
depends on ReplicationSlotValidateName?
I think we can go either way. It somewhat depends on whether we want
to backpatch this change. The argument for having this as a HEAD-only
patch is that, we have a similar behavior for other variables like
default_table_access_method and default_tablespace in HEAD and
back-branches. We want to change to a better behavior for this GUC, so
better to keep this as a HEAD-only patch. Do you or others have
thoughts on this matter?
If we decide to do this as a HEAD-only patch, then I think we can push
this without waiting for the other patch to commit as we have ample
time to get that done and we already have a solution as well for it.
OTOH, if we want to backpatch this then I would prefer to wait for the
other patch to be committed first.
--
With Regards,
Amit Kapila.
Hi,
On Wed, Sep 24, 2025 at 3:45 PM Amit Kapila <amit.kapila16@gmail.com> wrote:
On Wed, Sep 24, 2025 at 12:14 PM Ashutosh Sharma <ashu.coek88@gmail.com> wrote:
Hi Amit,
On Tue, Sep 23, 2025 at 1:00 PM Shlok Kyal <shlok.kyal.oss@gmail.com> wrote:
On Tue, 23 Sept 2025 at 09:55, Amit Kapila <amit.kapila16@gmail.com> wrote:
On Fri, Sep 12, 2025 at 2:34 PM Shlok Kyal <shlok.kyal.oss@gmail.com> wrote:
I have attached the updated v4 patch
+# Cannot be set synchronized_standby_slots to a reserved slot name +($result, $stdout, $stderr) = $primary->psql('postgres', + "ALTER SYSTEM SET synchronized_standby_slots='pg_conflict_detection'"); +ok( $stderr =~ + m/WARNING: replication slot name "pg_conflict_detection" is reserved/, + "Cannot use a reserverd slot name"); + +# Cannot be set synchronized_standby_slots to slot name with invalid characters +($result, $stdout, $stderr) = $primary->psql('postgres', + "ALTER SYSTEM SET synchronized_standby_slots='invalid*'"); +ok( $stderr =~ + m/WARNING: replication slot name "invalid\*" contains invalid character/, + "Cannot use a invalid slot name");These tests can be present in some sql file. I think you have kept
these in the .pl file to keep it along with other tests but I think
these are better suited for some .sql file.Thanks for reviewing the patch.
I have moved the tests to the guc.sql file. I have attached the updated patch.Are we planning to wait for [1] to go in first, since this also
depends on ReplicationSlotValidateName?I think we can go either way. It somewhat depends on whether we want
to backpatch this change. The argument for having this as a HEAD-only
patch is that, we have a similar behavior for other variables like
default_table_access_method and default_tablespace in HEAD and
back-branches. We want to change to a better behavior for this GUC, so
better to keep this as a HEAD-only patch. Do you or others have
thoughts on this matter?If we decide to do this as a HEAD-only patch, then I think we can push
this without waiting for the other patch to commit as we have ample
time to get that done and we already have a solution as well for it.
OTOH, if we want to backpatch this then I would prefer to wait for the
other patch to be committed first.
Although it's a behaviour change at GUC level, to me it doesn't look
like something that would break the user applications, so I'm inclined
toward backpatching it, but I'd definitely want to hear if others see
potential compatibility risks that I might be missing.
--
With Regards,
Ashutosh Sharma.
As Ashutosh suggests I will go more for the backpatching approach because
the synchronized_standby_slots parameter impacts the last 2 major versions
and this problem is critical on production environments.
Best regards
Fabrice
On Fri, Sep 26, 2025 at 9:00 AM Ashutosh Sharma <ashu.coek88@gmail.com>
wrote:
Show quoted text
Hi,
On Wed, Sep 24, 2025 at 3:45 PM Amit Kapila <amit.kapila16@gmail.com>
wrote:On Wed, Sep 24, 2025 at 12:14 PM Ashutosh Sharma <ashu.coek88@gmail.com>
wrote:
Hi Amit,
On Tue, Sep 23, 2025 at 1:00 PM Shlok Kyal <shlok.kyal.oss@gmail.com>
wrote:
On Tue, 23 Sept 2025 at 09:55, Amit Kapila <amit.kapila16@gmail.com>
wrote:
On Fri, Sep 12, 2025 at 2:34 PM Shlok Kyal <
shlok.kyal.oss@gmail.com> wrote:
I have attached the updated v4 patch
+# Cannot be set synchronized_standby_slots to a reserved slot name +($result, $stdout, $stderr) = $primary->psql('postgres', + "ALTER SYSTEM SETsynchronized_standby_slots='pg_conflict_detection'");
+ok( $stderr =~ + m/WARNING: replication slot name "pg_conflict_detection" isreserved/,
+ "Cannot use a reserverd slot name"); + +# Cannot be set synchronized_standby_slots to slot name withinvalid characters
+($result, $stdout, $stderr) = $primary->psql('postgres', + "ALTER SYSTEM SET synchronized_standby_slots='invalid*'"); +ok( $stderr =~ + m/WARNING: replication slot name "invalid\*" contains invalidcharacter/,
+ "Cannot use a invalid slot name");
These tests can be present in some sql file. I think you have kept
these in the .pl file to keep it along with other tests but I think
these are better suited for some .sql file.Thanks for reviewing the patch.
I have moved the tests to the guc.sql file. I have attached theupdated patch.
Are we planning to wait for [1] to go in first, since this also
depends on ReplicationSlotValidateName?I think we can go either way. It somewhat depends on whether we want
to backpatch this change. The argument for having this as a HEAD-only
patch is that, we have a similar behavior for other variables like
default_table_access_method and default_tablespace in HEAD and
back-branches. We want to change to a better behavior for this GUC, so
better to keep this as a HEAD-only patch. Do you or others have
thoughts on this matter?If we decide to do this as a HEAD-only patch, then I think we can push
this without waiting for the other patch to commit as we have ample
time to get that done and we already have a solution as well for it.
OTOH, if we want to backpatch this then I would prefer to wait for the
other patch to be committed first.Although it's a behaviour change at GUC level, to me it doesn't look
like something that would break the user applications, so I'm inclined
toward backpatching it, but I'd definitely want to hear if others see
potential compatibility risks that I might be missing.--
With Regards,
Ashutosh Sharma.
On Wed, Oct 8, 2025 at 9:05 PM Fabrice Chapuis <fabrice636861@gmail.com> wrote:
As Ashutosh suggests I will go more for the backpatching approach because the synchronized_standby_slots parameter impacts the last 2 major versions and this problem is critical on production environments.
Fair enough. Let's wait for the related issue being discussed in email
[1]: /messages/by-id/CAHGQGwFud-cvthCTfusBfKHBS6Jj6kdAPTdLWKvP2qjUX6L_wA@mail.gmail.com
[1]: /messages/by-id/CAHGQGwFud-cvthCTfusBfKHBS6Jj6kdAPTdLWKvP2qjUX6L_wA@mail.gmail.com
--
With Regards,
Amit Kapila.
On Thu, Oct 9, 2025 at 10:53 AM Amit Kapila <amit.kapila16@gmail.com> wrote:
On Wed, Oct 8, 2025 at 9:05 PM Fabrice Chapuis <fabrice636861@gmail.com> wrote:
As Ashutosh suggests I will go more for the backpatching approach because the synchronized_standby_slots parameter impacts the last 2 major versions and this problem is critical on production environments.
Fair enough. Let's wait for the related issue being discussed in email
[1] to be fixed.
As the other patch is committed
(f33e60a53a9ca89b5078df49416acae20affe1f5), can you update and prepare
backbranch patches for this fix as well?
--
With Regards,
Amit Kapila.
On Thu, 23 Oct 2025 at 09:36, Amit Kapila <amit.kapila16@gmail.com> wrote:
On Thu, Oct 9, 2025 at 10:53 AM Amit Kapila <amit.kapila16@gmail.com> wrote:
On Wed, Oct 8, 2025 at 9:05 PM Fabrice Chapuis <fabrice636861@gmail.com> wrote:
As Ashutosh suggests I will go more for the backpatching approach because the synchronized_standby_slots parameter impacts the last 2 major versions and this problem is critical on production environments.
Fair enough. Let's wait for the related issue being discussed in email
[1] to be fixed.As the other patch is committed
(f33e60a53a9ca89b5078df49416acae20affe1f5), can you update and prepare
backbranch patches for this fix as well?
Hi Amit,
Please find the updated patch.
v6-0001 : It applies on HEAD and REL_18_STABLE branches
v6_REL_17-0001 : It applies on REL_17_STABLE branch.
Since this GUC was introduced in PG_17, we do not need to back-patch
to PG_16 or prior.
Thanks,
Shlok Kyal
Attachments:
v6_REL_17-0001-Remove-the-validation-from-the-GUC-check-h.patchapplication/octet-stream; name=v6_REL_17-0001-Remove-the-validation-from-the-GUC-check-h.patchDownload
From 8d37e280aee3a2e99888b1ab96d1d3ffe779ba8d Mon Sep 17 00:00:00 2001
From: Shlok Kyal <shlok.kyal.oss@gmail.com>
Date: Thu, 23 Oct 2025 11:09:47 +0530
Subject: [PATCH v6_REL_17] Remove the validation from the GUC check hook and
add parsing check
The validation in check_synchronized_standby_slots cannot be run
in postmaster and hence can result inconsistent values in some
backends that inherit the value from postmaster and those
that are started newly. Also, this validation results in parallel
workers fail to with error. This causes all the commands run by
parallel workers to fail, which seems unnecesary. This validation
already happens in StandbySlotsHaveCaughtup() where this GUC is
used, so it can be removed from the GUC check. Also added a
parsing check for the slot names specified in this GUC.
---
src/backend/replication/slot.c | 58 ++++++++-----------------------
src/test/regress/expected/guc.out | 26 ++++++++++++++
src/test/regress/sql/guc.sql | 16 +++++++++
3 files changed, 57 insertions(+), 43 deletions(-)
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 80b8abde3a2..e2a16a513a9 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -2468,53 +2468,31 @@ GetSlotInvalidationCause(const char *invalidation_reason)
static bool
validate_sync_standby_slots(char *rawname, List **elemlist)
{
- bool ok;
-
/* Verify syntax and parse string into a list of identifiers */
- ok = SplitIdentifierString(rawname, ',', elemlist);
-
- if (!ok)
+ if (!SplitIdentifierString(rawname, ',', elemlist))
{
GUC_check_errdetail("List syntax is invalid.");
+ return false;
}
- else if (MyProc)
+
+ foreach_ptr(char, name, *elemlist)
{
- /*
- * Check that each specified slot exist and is physical.
- *
- * Because we need an LWLock, we cannot do this on processes without a
- * PGPROC, so we skip it there; but see comments in
- * StandbySlotsHaveCaughtup() as to why that's not a problem.
- */
- LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
+ int err_code;
+ char *err_msg = NULL;
+ char *err_hint = NULL;
- foreach_ptr(char, name, *elemlist)
+ if (!ReplicationSlotValidateNameInternal(name, &err_code, &err_msg,
+ &err_hint))
{
- ReplicationSlot *slot;
-
- slot = SearchNamedReplicationSlot(name, false);
-
- if (!slot)
- {
- GUC_check_errdetail("replication slot \"%s\" does not exist",
- name);
- ok = false;
- break;
- }
-
- if (!SlotIsPhysical(slot))
- {
- GUC_check_errdetail("\"%s\" is not a physical replication slot",
- name);
- ok = false;
- break;
- }
+ GUC_check_errcode(err_code);
+ GUC_check_errdetail("%s", err_msg);
+ if (err_hint != NULL)
+ GUC_check_errhint("%s", err_hint);
+ return false;
}
-
- LWLockRelease(ReplicationSlotControlLock);
}
- return ok;
+ return true;
}
/*
@@ -2672,12 +2650,6 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
/*
* If a slot name provided in synchronized_standby_slots does not
* exist, report a message and exit the loop.
- *
- * Though validate_sync_standby_slots (the GUC check_hook) tries to
- * avoid this, it can nonetheless happen because the user can specify
- * a nonexistent slot name before server startup. That function cannot
- * validate such a slot during startup, as ReplicationSlotCtl is not
- * initialized by then. Also, the user might have dropped one slot.
*/
if (!slot)
{
diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out
index 455b6d6c0ce..efb845f0339 100644
--- a/src/test/regress/expected/guc.out
+++ b/src/test/regress/expected/guc.out
@@ -888,3 +888,29 @@ SELECT name FROM tab_settings_flags
(0 rows)
DROP TABLE tab_settings_flags;
+-- Test for GUC synchronized standby slots
+-- Cannot set synchronized_standby_slots to a invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+ERROR: invalid value for parameter "synchronized_standby_slots": "invalid*"
+DETAIL: replication slot name "invalid*" contains invalid character
+HINT: Replication slot names may only contain lower case letters, numbers, and the underscore character.
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+SELECT pg_reload_conf();
+ pg_reload_conf
+----------------
+ t
+(1 row)
+
+-- Parallel worker does not throw error during startup.
+SET min_parallel_table_scan_size TO 0;
+SET parallel_setup_cost TO 0;
+SET parallel_tuple_cost TO 0;
+CREATE TABLE t1(a int);
+INSERT INTO t1 VALUES(1), (2), (3), (4);
+SELECT count(*) FROM t1;
+ count
+-------
+ 4
+(1 row)
+
diff --git a/src/test/regress/sql/guc.sql b/src/test/regress/sql/guc.sql
index dc79761955d..c0c6c9f98a2 100644
--- a/src/test/regress/sql/guc.sql
+++ b/src/test/regress/sql/guc.sql
@@ -353,3 +353,19 @@ SELECT name FROM tab_settings_flags
WHERE no_reset AND NOT no_reset_all
ORDER BY 1;
DROP TABLE tab_settings_flags;
+
+-- Test for GUC synchronized standby slots
+-- Cannot set synchronized_standby_slots to a invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+SELECT pg_reload_conf();
+
+-- Parallel worker does not throw error during startup.
+SET min_parallel_table_scan_size TO 0;
+SET parallel_setup_cost TO 0;
+SET parallel_tuple_cost TO 0;
+CREATE TABLE t1(a int);
+INSERT INTO t1 VALUES(1), (2), (3), (4);
+SELECT count(*) FROM t1;
--
2.34.1
v6-0001-Remove-the-validation-from-the-GUC-check-hook-and.patchapplication/octet-stream; name=v6-0001-Remove-the-validation-from-the-GUC-check-hook-and.patchDownload
From 99cfae8fdf7b0be34d33531f576185185bad68c1 Mon Sep 17 00:00:00 2001
From: Shlok Kyal <shlok.kyal.oss@gmail.com>
Date: Wed, 10 Sep 2025 15:08:23 +0530
Subject: [PATCH v6] Remove the validation from the GUC check hook and add
parsing check
The validation in check_synchronized_standby_slots cannot be run
in postmaster and hence can result inconsistent values in some
backends that inherit the value from postmaster and those
that are started newly. Also, this validation results in parallel
workers fail to with error. This causes all the commands run by
parallel workers to fail, which seems unnecesary. This validation
already happens in StandbySlotsHaveCaughtup() where this GUC is
used, so it can be removed from the GUC check. Also added a
parsing check for the slot names specified in this GUC.
---
src/backend/replication/slot.c | 58 ++++++++-----------------------
src/test/regress/expected/guc.out | 31 +++++++++++++++++
src/test/regress/sql/guc.sql | 19 ++++++++++
3 files changed, 65 insertions(+), 43 deletions(-)
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index a4ca363f20d..6b3d97d9ca8 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -2784,53 +2784,31 @@ GetSlotInvalidationCauseName(ReplicationSlotInvalidationCause cause)
static bool
validate_sync_standby_slots(char *rawname, List **elemlist)
{
- bool ok;
-
/* Verify syntax and parse string into a list of identifiers */
- ok = SplitIdentifierString(rawname, ',', elemlist);
-
- if (!ok)
+ if (!SplitIdentifierString(rawname, ',', elemlist))
{
GUC_check_errdetail("List syntax is invalid.");
+ return false;
}
- else if (MyProc)
+
+ foreach_ptr(char, name, *elemlist)
{
- /*
- * Check that each specified slot exist and is physical.
- *
- * Because we need an LWLock, we cannot do this on processes without a
- * PGPROC, so we skip it there; but see comments in
- * StandbySlotsHaveCaughtup() as to why that's not a problem.
- */
- LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
+ int err_code;
+ char *err_msg = NULL;
+ char *err_hint = NULL;
- foreach_ptr(char, name, *elemlist)
+ if (!ReplicationSlotValidateNameInternal(name, false, &err_code,
+ &err_msg, &err_hint))
{
- ReplicationSlot *slot;
-
- slot = SearchNamedReplicationSlot(name, false);
-
- if (!slot)
- {
- GUC_check_errdetail("Replication slot \"%s\" does not exist.",
- name);
- ok = false;
- break;
- }
-
- if (!SlotIsPhysical(slot))
- {
- GUC_check_errdetail("\"%s\" is not a physical replication slot.",
- name);
- ok = false;
- break;
- }
+ GUC_check_errcode(err_code);
+ GUC_check_errdetail("%s", err_msg);
+ if (err_hint != NULL)
+ GUC_check_errhint("%s", err_hint);
+ return false;
}
-
- LWLockRelease(ReplicationSlotControlLock);
}
- return ok;
+ return true;
}
/*
@@ -2988,12 +2966,6 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
/*
* If a slot name provided in synchronized_standby_slots does not
* exist, report a message and exit the loop.
- *
- * Though validate_sync_standby_slots (the GUC check_hook) tries to
- * avoid this, it can nonetheless happen because the user can specify
- * a nonexistent slot name before server startup. That function cannot
- * validate such a slot during startup, as ReplicationSlotCtl is not
- * initialized by then. Also, the user might have dropped one slot.
*/
if (!slot)
{
diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out
index 7f9e29c765c..4d9273d606f 100644
--- a/src/test/regress/expected/guc.out
+++ b/src/test/regress/expected/guc.out
@@ -913,3 +913,34 @@ SELECT name FROM tab_settings_flags
(0 rows)
DROP TABLE tab_settings_flags;
+-- Test for GUC synchronized standby slots
+-- Cannot set synchronized_standby_slots to a reserved slot name.
+ALTER SYSTEM SET synchronized_standby_slots='pg_conflict_detection';
+ERROR: invalid value for parameter "synchronized_standby_slots": "pg_conflict_detection"
+DETAIL: replication slot name "pg_conflict_detection" is reserved
+HINT: The name "pg_conflict_detection" is reserved for the conflict detection slot.
+-- Cannot set synchronized_standby_slots to a invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+ERROR: invalid value for parameter "synchronized_standby_slots": "invalid*"
+DETAIL: replication slot name "invalid*" contains invalid character
+HINT: Replication slot names may only contain lower case letters, numbers, and the underscore character.
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+SELECT pg_reload_conf();
+ pg_reload_conf
+----------------
+ t
+(1 row)
+
+-- Parallel worker does not throw error during startup.
+SET min_parallel_table_scan_size TO 0;
+SET parallel_setup_cost TO 0;
+SET parallel_tuple_cost TO 0;
+CREATE TABLE t1(a int);
+INSERT INTO t1 VALUES(1), (2), (3), (4);
+SELECT count(*) FROM t1;
+ count
+-------
+ 4
+(1 row)
+
diff --git a/src/test/regress/sql/guc.sql b/src/test/regress/sql/guc.sql
index f65f84a2632..3e8e7d5c63a 100644
--- a/src/test/regress/sql/guc.sql
+++ b/src/test/regress/sql/guc.sql
@@ -368,3 +368,22 @@ SELECT name FROM tab_settings_flags
WHERE no_reset AND NOT no_reset_all
ORDER BY 1;
DROP TABLE tab_settings_flags;
+
+-- Test for GUC synchronized standby slots
+-- Cannot set synchronized_standby_slots to a reserved slot name.
+ALTER SYSTEM SET synchronized_standby_slots='pg_conflict_detection';
+
+-- Cannot set synchronized_standby_slots to a invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+SELECT pg_reload_conf();
+
+-- Parallel worker does not throw error during startup.
+SET min_parallel_table_scan_size TO 0;
+SET parallel_setup_cost TO 0;
+SET parallel_tuple_cost TO 0;
+CREATE TABLE t1(a int);
+INSERT INTO t1 VALUES(1), (2), (3), (4);
+SELECT count(*) FROM t1;
--
2.34.1
On Thu, 23 Oct 2025 at 13:19, Shlok Kyal <shlok.kyal.oss@gmail.com> wrote:
On Thu, 23 Oct 2025 at 09:36, Amit Kapila <amit.kapila16@gmail.com> wrote:
On Thu, Oct 9, 2025 at 10:53 AM Amit Kapila <amit.kapila16@gmail.com> wrote:
On Wed, Oct 8, 2025 at 9:05 PM Fabrice Chapuis <fabrice636861@gmail.com> wrote:
As Ashutosh suggests I will go more for the backpatching approach because the synchronized_standby_slots parameter impacts the last 2 major versions and this problem is critical on production environments.
Fair enough. Let's wait for the related issue being discussed in email
[1] to be fixed.As the other patch is committed
(f33e60a53a9ca89b5078df49416acae20affe1f5), can you update and prepare
backbranch patches for this fix as well?Hi Amit,
Please find the updated patch.
v6-0001 : It applies on HEAD and REL_18_STABLE branches
v6_REL_17-0001 : It applies on REL_17_STABLE branch.Since this GUC was introduced in PG_17, we do not need to back-patch
to PG_16 or prior.
The CFbot was failing due to the merge conflict. It happened because
CFbot tried to apply v6_REL_17 on top of v6-0001 patch. Added
v6_REL_17 as a .txt file so this merge conflict do not happen.
Thanks,
Shlok Kyal
Attachments:
v6_REL_17-0001-Remove-the-validation-from-the-GUC-check-h.txttext/plain; charset=US-ASCII; name=v6_REL_17-0001-Remove-the-validation-from-the-GUC-check-h.txtDownload
From 8d37e280aee3a2e99888b1ab96d1d3ffe779ba8d Mon Sep 17 00:00:00 2001
From: Shlok Kyal <shlok.kyal.oss@gmail.com>
Date: Thu, 23 Oct 2025 11:09:47 +0530
Subject: [PATCH v6_REL_17] Remove the validation from the GUC check hook and
add parsing check
The validation in check_synchronized_standby_slots cannot be run
in postmaster and hence can result inconsistent values in some
backends that inherit the value from postmaster and those
that are started newly. Also, this validation results in parallel
workers fail to with error. This causes all the commands run by
parallel workers to fail, which seems unnecesary. This validation
already happens in StandbySlotsHaveCaughtup() where this GUC is
used, so it can be removed from the GUC check. Also added a
parsing check for the slot names specified in this GUC.
---
src/backend/replication/slot.c | 58 ++++++++-----------------------
src/test/regress/expected/guc.out | 26 ++++++++++++++
src/test/regress/sql/guc.sql | 16 +++++++++
3 files changed, 57 insertions(+), 43 deletions(-)
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 80b8abde3a2..e2a16a513a9 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -2468,53 +2468,31 @@ GetSlotInvalidationCause(const char *invalidation_reason)
static bool
validate_sync_standby_slots(char *rawname, List **elemlist)
{
- bool ok;
-
/* Verify syntax and parse string into a list of identifiers */
- ok = SplitIdentifierString(rawname, ',', elemlist);
-
- if (!ok)
+ if (!SplitIdentifierString(rawname, ',', elemlist))
{
GUC_check_errdetail("List syntax is invalid.");
+ return false;
}
- else if (MyProc)
+
+ foreach_ptr(char, name, *elemlist)
{
- /*
- * Check that each specified slot exist and is physical.
- *
- * Because we need an LWLock, we cannot do this on processes without a
- * PGPROC, so we skip it there; but see comments in
- * StandbySlotsHaveCaughtup() as to why that's not a problem.
- */
- LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
+ int err_code;
+ char *err_msg = NULL;
+ char *err_hint = NULL;
- foreach_ptr(char, name, *elemlist)
+ if (!ReplicationSlotValidateNameInternal(name, &err_code, &err_msg,
+ &err_hint))
{
- ReplicationSlot *slot;
-
- slot = SearchNamedReplicationSlot(name, false);
-
- if (!slot)
- {
- GUC_check_errdetail("replication slot \"%s\" does not exist",
- name);
- ok = false;
- break;
- }
-
- if (!SlotIsPhysical(slot))
- {
- GUC_check_errdetail("\"%s\" is not a physical replication slot",
- name);
- ok = false;
- break;
- }
+ GUC_check_errcode(err_code);
+ GUC_check_errdetail("%s", err_msg);
+ if (err_hint != NULL)
+ GUC_check_errhint("%s", err_hint);
+ return false;
}
-
- LWLockRelease(ReplicationSlotControlLock);
}
- return ok;
+ return true;
}
/*
@@ -2672,12 +2650,6 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
/*
* If a slot name provided in synchronized_standby_slots does not
* exist, report a message and exit the loop.
- *
- * Though validate_sync_standby_slots (the GUC check_hook) tries to
- * avoid this, it can nonetheless happen because the user can specify
- * a nonexistent slot name before server startup. That function cannot
- * validate such a slot during startup, as ReplicationSlotCtl is not
- * initialized by then. Also, the user might have dropped one slot.
*/
if (!slot)
{
diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out
index 455b6d6c0ce..efb845f0339 100644
--- a/src/test/regress/expected/guc.out
+++ b/src/test/regress/expected/guc.out
@@ -888,3 +888,29 @@ SELECT name FROM tab_settings_flags
(0 rows)
DROP TABLE tab_settings_flags;
+-- Test for GUC synchronized standby slots
+-- Cannot set synchronized_standby_slots to a invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+ERROR: invalid value for parameter "synchronized_standby_slots": "invalid*"
+DETAIL: replication slot name "invalid*" contains invalid character
+HINT: Replication slot names may only contain lower case letters, numbers, and the underscore character.
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+SELECT pg_reload_conf();
+ pg_reload_conf
+----------------
+ t
+(1 row)
+
+-- Parallel worker does not throw error during startup.
+SET min_parallel_table_scan_size TO 0;
+SET parallel_setup_cost TO 0;
+SET parallel_tuple_cost TO 0;
+CREATE TABLE t1(a int);
+INSERT INTO t1 VALUES(1), (2), (3), (4);
+SELECT count(*) FROM t1;
+ count
+-------
+ 4
+(1 row)
+
diff --git a/src/test/regress/sql/guc.sql b/src/test/regress/sql/guc.sql
index dc79761955d..c0c6c9f98a2 100644
--- a/src/test/regress/sql/guc.sql
+++ b/src/test/regress/sql/guc.sql
@@ -353,3 +353,19 @@ SELECT name FROM tab_settings_flags
WHERE no_reset AND NOT no_reset_all
ORDER BY 1;
DROP TABLE tab_settings_flags;
+
+-- Test for GUC synchronized standby slots
+-- Cannot set synchronized_standby_slots to a invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+SELECT pg_reload_conf();
+
+-- Parallel worker does not throw error during startup.
+SET min_parallel_table_scan_size TO 0;
+SET parallel_setup_cost TO 0;
+SET parallel_tuple_cost TO 0;
+CREATE TABLE t1(a int);
+INSERT INTO t1 VALUES(1), (2), (3), (4);
+SELECT count(*) FROM t1;
--
2.34.1
v6-0001-Remove-the-validation-from-the-GUC-check-hook-and.patchapplication/octet-stream; name=v6-0001-Remove-the-validation-from-the-GUC-check-hook-and.patchDownload
From 99cfae8fdf7b0be34d33531f576185185bad68c1 Mon Sep 17 00:00:00 2001
From: Shlok Kyal <shlok.kyal.oss@gmail.com>
Date: Wed, 10 Sep 2025 15:08:23 +0530
Subject: [PATCH v6] Remove the validation from the GUC check hook and add
parsing check
The validation in check_synchronized_standby_slots cannot be run
in postmaster and hence can result inconsistent values in some
backends that inherit the value from postmaster and those
that are started newly. Also, this validation results in parallel
workers fail to with error. This causes all the commands run by
parallel workers to fail, which seems unnecesary. This validation
already happens in StandbySlotsHaveCaughtup() where this GUC is
used, so it can be removed from the GUC check. Also added a
parsing check for the slot names specified in this GUC.
---
src/backend/replication/slot.c | 58 ++++++++-----------------------
src/test/regress/expected/guc.out | 31 +++++++++++++++++
src/test/regress/sql/guc.sql | 19 ++++++++++
3 files changed, 65 insertions(+), 43 deletions(-)
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index a4ca363f20d..6b3d97d9ca8 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -2784,53 +2784,31 @@ GetSlotInvalidationCauseName(ReplicationSlotInvalidationCause cause)
static bool
validate_sync_standby_slots(char *rawname, List **elemlist)
{
- bool ok;
-
/* Verify syntax and parse string into a list of identifiers */
- ok = SplitIdentifierString(rawname, ',', elemlist);
-
- if (!ok)
+ if (!SplitIdentifierString(rawname, ',', elemlist))
{
GUC_check_errdetail("List syntax is invalid.");
+ return false;
}
- else if (MyProc)
+
+ foreach_ptr(char, name, *elemlist)
{
- /*
- * Check that each specified slot exist and is physical.
- *
- * Because we need an LWLock, we cannot do this on processes without a
- * PGPROC, so we skip it there; but see comments in
- * StandbySlotsHaveCaughtup() as to why that's not a problem.
- */
- LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
+ int err_code;
+ char *err_msg = NULL;
+ char *err_hint = NULL;
- foreach_ptr(char, name, *elemlist)
+ if (!ReplicationSlotValidateNameInternal(name, false, &err_code,
+ &err_msg, &err_hint))
{
- ReplicationSlot *slot;
-
- slot = SearchNamedReplicationSlot(name, false);
-
- if (!slot)
- {
- GUC_check_errdetail("Replication slot \"%s\" does not exist.",
- name);
- ok = false;
- break;
- }
-
- if (!SlotIsPhysical(slot))
- {
- GUC_check_errdetail("\"%s\" is not a physical replication slot.",
- name);
- ok = false;
- break;
- }
+ GUC_check_errcode(err_code);
+ GUC_check_errdetail("%s", err_msg);
+ if (err_hint != NULL)
+ GUC_check_errhint("%s", err_hint);
+ return false;
}
-
- LWLockRelease(ReplicationSlotControlLock);
}
- return ok;
+ return true;
}
/*
@@ -2988,12 +2966,6 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
/*
* If a slot name provided in synchronized_standby_slots does not
* exist, report a message and exit the loop.
- *
- * Though validate_sync_standby_slots (the GUC check_hook) tries to
- * avoid this, it can nonetheless happen because the user can specify
- * a nonexistent slot name before server startup. That function cannot
- * validate such a slot during startup, as ReplicationSlotCtl is not
- * initialized by then. Also, the user might have dropped one slot.
*/
if (!slot)
{
diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out
index 7f9e29c765c..4d9273d606f 100644
--- a/src/test/regress/expected/guc.out
+++ b/src/test/regress/expected/guc.out
@@ -913,3 +913,34 @@ SELECT name FROM tab_settings_flags
(0 rows)
DROP TABLE tab_settings_flags;
+-- Test for GUC synchronized standby slots
+-- Cannot set synchronized_standby_slots to a reserved slot name.
+ALTER SYSTEM SET synchronized_standby_slots='pg_conflict_detection';
+ERROR: invalid value for parameter "synchronized_standby_slots": "pg_conflict_detection"
+DETAIL: replication slot name "pg_conflict_detection" is reserved
+HINT: The name "pg_conflict_detection" is reserved for the conflict detection slot.
+-- Cannot set synchronized_standby_slots to a invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+ERROR: invalid value for parameter "synchronized_standby_slots": "invalid*"
+DETAIL: replication slot name "invalid*" contains invalid character
+HINT: Replication slot names may only contain lower case letters, numbers, and the underscore character.
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+SELECT pg_reload_conf();
+ pg_reload_conf
+----------------
+ t
+(1 row)
+
+-- Parallel worker does not throw error during startup.
+SET min_parallel_table_scan_size TO 0;
+SET parallel_setup_cost TO 0;
+SET parallel_tuple_cost TO 0;
+CREATE TABLE t1(a int);
+INSERT INTO t1 VALUES(1), (2), (3), (4);
+SELECT count(*) FROM t1;
+ count
+-------
+ 4
+(1 row)
+
diff --git a/src/test/regress/sql/guc.sql b/src/test/regress/sql/guc.sql
index f65f84a2632..3e8e7d5c63a 100644
--- a/src/test/regress/sql/guc.sql
+++ b/src/test/regress/sql/guc.sql
@@ -368,3 +368,22 @@ SELECT name FROM tab_settings_flags
WHERE no_reset AND NOT no_reset_all
ORDER BY 1;
DROP TABLE tab_settings_flags;
+
+-- Test for GUC synchronized standby slots
+-- Cannot set synchronized_standby_slots to a reserved slot name.
+ALTER SYSTEM SET synchronized_standby_slots='pg_conflict_detection';
+
+-- Cannot set synchronized_standby_slots to a invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+SELECT pg_reload_conf();
+
+-- Parallel worker does not throw error during startup.
+SET min_parallel_table_scan_size TO 0;
+SET parallel_setup_cost TO 0;
+SET parallel_tuple_cost TO 0;
+CREATE TABLE t1(a int);
+INSERT INTO t1 VALUES(1), (2), (3), (4);
+SELECT count(*) FROM t1;
--
2.34.1
Dear Shlok,
Thanks for updating the patch! Few comments.
1.
You must separate patch for master and PG18, because ReplicationSlotValidateNameInternal()
does not accept `bool allow_reserved_name` in the version.
2.
Also, test for PG18 should not have the case which rejects the reserved name.
3.
```
-- Parallel worker does not throw error during startup.
SET min_parallel_table_scan_size TO 0;
SET parallel_setup_cost TO 0;
SET parallel_tuple_cost TO 0;
```
According to contrib/pg_stat_statements/sql/parallel.sql, max_parallel_workers_per_gather
should be also set. There is a possiblity that `make installcheck` is used and
it has max_parallel_workers_per_gather=0.
4.
```
foreach_ptr(char, name, *elemlist)
```
You can add a comment atop here like:
Iterate the list to validate each slot name.
Best regards,
Hayato Kuroda
FUJITSU LIMITED
On Thu, 23 Oct 2025 at 13:45, Hayato Kuroda (Fujitsu)
<kuroda.hayato@fujitsu.com> wrote:
Dear Shlok,
Thanks for updating the patch! Few comments.
1.
You must separate patch for master and PG18, because ReplicationSlotValidateNameInternal()
does not accept `bool allow_reserved_name` in the version.2.
Also, test for PG18 should not have the case which rejects the reserved name.3.
```
-- Parallel worker does not throw error during startup.
SET min_parallel_table_scan_size TO 0;
SET parallel_setup_cost TO 0;
SET parallel_tuple_cost TO 0;
```According to contrib/pg_stat_statements/sql/parallel.sql, max_parallel_workers_per_gather
should be also set. There is a possiblity that `make installcheck` is used and
it has max_parallel_workers_per_gather=0.4.
```
foreach_ptr(char, name, *elemlist)
```You can add a comment atop here like:
Iterate the list to validate each slot name.
Hi Kuroda-san,
Thanks for reviewing the patches.
I have addressed the comments and attached the updated version.
Thanks,
Shlok Kyal
Attachments:
v7_REL_17-0001-Remove-the-validation-from-the-GUC-check-h.txttext/plain; charset=US-ASCII; name=v7_REL_17-0001-Remove-the-validation-from-the-GUC-check-h.txtDownload
From 966f431cd4bb0a599be15d034778c5338f217d6c Mon Sep 17 00:00:00 2001
From: Shlok Kyal <shlok.kyal.oss@gmail.com>
Date: Thu, 23 Oct 2025 11:09:47 +0530
Subject: [PATCH v7_REL_17] Remove the validation from the GUC check hook and
add parsing check
The validation in check_synchronized_standby_slots cannot be run
in postmaster and hence can result inconsistent values in some
backends that inherit the value from postmaster and those
that are started newly. Also, this validation results in parallel
workers fail to with error. This causes all the commands run by
parallel workers to fail, which seems unnecesary. This validation
already happens in StandbySlotsHaveCaughtup() where this GUC is
used, so it can be removed from the GUC check. Also added a
parsing check for the slot names specified in this GUC.
---
src/backend/replication/slot.c | 59 +++++++++----------------------
src/test/regress/expected/guc.out | 27 ++++++++++++++
src/test/regress/sql/guc.sql | 17 +++++++++
3 files changed, 60 insertions(+), 43 deletions(-)
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 80b8abde3a2..4bc2be33396 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -2468,53 +2468,32 @@ GetSlotInvalidationCause(const char *invalidation_reason)
static bool
validate_sync_standby_slots(char *rawname, List **elemlist)
{
- bool ok;
-
/* Verify syntax and parse string into a list of identifiers */
- ok = SplitIdentifierString(rawname, ',', elemlist);
-
- if (!ok)
+ if (!SplitIdentifierString(rawname, ',', elemlist))
{
GUC_check_errdetail("List syntax is invalid.");
+ return false;
}
- else if (MyProc)
+
+ /* Iterate the list to validate each slot name */
+ foreach_ptr(char, name, *elemlist)
{
- /*
- * Check that each specified slot exist and is physical.
- *
- * Because we need an LWLock, we cannot do this on processes without a
- * PGPROC, so we skip it there; but see comments in
- * StandbySlotsHaveCaughtup() as to why that's not a problem.
- */
- LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
+ int err_code;
+ char *err_msg = NULL;
+ char *err_hint = NULL;
- foreach_ptr(char, name, *elemlist)
+ if (!ReplicationSlotValidateNameInternal(name, &err_code, &err_msg,
+ &err_hint))
{
- ReplicationSlot *slot;
-
- slot = SearchNamedReplicationSlot(name, false);
-
- if (!slot)
- {
- GUC_check_errdetail("replication slot \"%s\" does not exist",
- name);
- ok = false;
- break;
- }
-
- if (!SlotIsPhysical(slot))
- {
- GUC_check_errdetail("\"%s\" is not a physical replication slot",
- name);
- ok = false;
- break;
- }
+ GUC_check_errcode(err_code);
+ GUC_check_errdetail("%s", err_msg);
+ if (err_hint != NULL)
+ GUC_check_errhint("%s", err_hint);
+ return false;
}
-
- LWLockRelease(ReplicationSlotControlLock);
}
- return ok;
+ return true;
}
/*
@@ -2672,12 +2651,6 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
/*
* If a slot name provided in synchronized_standby_slots does not
* exist, report a message and exit the loop.
- *
- * Though validate_sync_standby_slots (the GUC check_hook) tries to
- * avoid this, it can nonetheless happen because the user can specify
- * a nonexistent slot name before server startup. That function cannot
- * validate such a slot during startup, as ReplicationSlotCtl is not
- * initialized by then. Also, the user might have dropped one slot.
*/
if (!slot)
{
diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out
index 455b6d6c0ce..e5f8d84f5c5 100644
--- a/src/test/regress/expected/guc.out
+++ b/src/test/regress/expected/guc.out
@@ -888,3 +888,30 @@ SELECT name FROM tab_settings_flags
(0 rows)
DROP TABLE tab_settings_flags;
+-- Test for GUC synchronized standby slots
+-- Cannot set synchronized_standby_slots to a invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+ERROR: invalid value for parameter "synchronized_standby_slots": "invalid*"
+DETAIL: replication slot name "invalid*" contains invalid character
+HINT: Replication slot names may only contain lower case letters, numbers, and the underscore character.
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+SELECT pg_reload_conf();
+ pg_reload_conf
+----------------
+ t
+(1 row)
+
+-- Parallel worker does not throw error during startup.
+SET min_parallel_table_scan_size TO 0;
+SET max_parallel_workers_per_gather TO 2;
+SET parallel_setup_cost TO 0;
+SET parallel_tuple_cost TO 0;
+CREATE TABLE t1(a int);
+INSERT INTO t1 VALUES(1), (2), (3), (4);
+SELECT count(*) FROM t1;
+ count
+-------
+ 4
+(1 row)
+
diff --git a/src/test/regress/sql/guc.sql b/src/test/regress/sql/guc.sql
index dc79761955d..ee75ca04bbd 100644
--- a/src/test/regress/sql/guc.sql
+++ b/src/test/regress/sql/guc.sql
@@ -353,3 +353,20 @@ SELECT name FROM tab_settings_flags
WHERE no_reset AND NOT no_reset_all
ORDER BY 1;
DROP TABLE tab_settings_flags;
+
+-- Test for GUC synchronized standby slots
+-- Cannot set synchronized_standby_slots to a invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+SELECT pg_reload_conf();
+
+-- Parallel worker does not throw error during startup.
+SET min_parallel_table_scan_size TO 0;
+SET max_parallel_workers_per_gather TO 2;
+SET parallel_setup_cost TO 0;
+SET parallel_tuple_cost TO 0;
+CREATE TABLE t1(a int);
+INSERT INTO t1 VALUES(1), (2), (3), (4);
+SELECT count(*) FROM t1;
--
2.34.1
v7_HEAD-0001-Remove-the-validation-from-the-GUC-check-hoo.patchapplication/octet-stream; name=v7_HEAD-0001-Remove-the-validation-from-the-GUC-check-hoo.patchDownload
From f49ca590b9aa5bf23e4c6b1662bdc97d7b46c070 Mon Sep 17 00:00:00 2001
From: Shlok Kyal <shlok.kyal.oss@gmail.com>
Date: Wed, 10 Sep 2025 15:08:23 +0530
Subject: [PATCH v7_HEAD] Remove the validation from the GUC check hook and add
parsing check
The validation in check_synchronized_standby_slots cannot be run
in postmaster and hence can result inconsistent values in some
backends that inherit the value from postmaster and those
that are started newly. Also, this validation results in parallel
workers fail to with error. This causes all the commands run by
parallel workers to fail, which seems unnecesary. This validation
already happens in StandbySlotsHaveCaughtup() where this GUC is
used, so it can be removed from the GUC check. Also added a
parsing check for the slot names specified in this GUC.
---
src/backend/replication/slot.c | 59 +++++++++----------------------
src/test/regress/expected/guc.out | 32 +++++++++++++++++
src/test/regress/sql/guc.sql | 20 +++++++++++
3 files changed, 68 insertions(+), 43 deletions(-)
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index a4ca363f20d..1e9f4602c69 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -2784,53 +2784,32 @@ GetSlotInvalidationCauseName(ReplicationSlotInvalidationCause cause)
static bool
validate_sync_standby_slots(char *rawname, List **elemlist)
{
- bool ok;
-
/* Verify syntax and parse string into a list of identifiers */
- ok = SplitIdentifierString(rawname, ',', elemlist);
-
- if (!ok)
+ if (!SplitIdentifierString(rawname, ',', elemlist))
{
GUC_check_errdetail("List syntax is invalid.");
+ return false;
}
- else if (MyProc)
+
+ /* Iterate the list to validate each slot name */
+ foreach_ptr(char, name, *elemlist)
{
- /*
- * Check that each specified slot exist and is physical.
- *
- * Because we need an LWLock, we cannot do this on processes without a
- * PGPROC, so we skip it there; but see comments in
- * StandbySlotsHaveCaughtup() as to why that's not a problem.
- */
- LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
+ int err_code;
+ char *err_msg = NULL;
+ char *err_hint = NULL;
- foreach_ptr(char, name, *elemlist)
+ if (!ReplicationSlotValidateNameInternal(name, false, &err_code,
+ &err_msg, &err_hint))
{
- ReplicationSlot *slot;
-
- slot = SearchNamedReplicationSlot(name, false);
-
- if (!slot)
- {
- GUC_check_errdetail("Replication slot \"%s\" does not exist.",
- name);
- ok = false;
- break;
- }
-
- if (!SlotIsPhysical(slot))
- {
- GUC_check_errdetail("\"%s\" is not a physical replication slot.",
- name);
- ok = false;
- break;
- }
+ GUC_check_errcode(err_code);
+ GUC_check_errdetail("%s", err_msg);
+ if (err_hint != NULL)
+ GUC_check_errhint("%s", err_hint);
+ return false;
}
-
- LWLockRelease(ReplicationSlotControlLock);
}
- return ok;
+ return true;
}
/*
@@ -2988,12 +2967,6 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
/*
* If a slot name provided in synchronized_standby_slots does not
* exist, report a message and exit the loop.
- *
- * Though validate_sync_standby_slots (the GUC check_hook) tries to
- * avoid this, it can nonetheless happen because the user can specify
- * a nonexistent slot name before server startup. That function cannot
- * validate such a slot during startup, as ReplicationSlotCtl is not
- * initialized by then. Also, the user might have dropped one slot.
*/
if (!slot)
{
diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out
index 7f9e29c765c..8ea2b5a891e 100644
--- a/src/test/regress/expected/guc.out
+++ b/src/test/regress/expected/guc.out
@@ -913,3 +913,35 @@ SELECT name FROM tab_settings_flags
(0 rows)
DROP TABLE tab_settings_flags;
+-- Test for GUC synchronized standby slots
+-- Cannot set synchronized_standby_slots to a reserved slot name.
+ALTER SYSTEM SET synchronized_standby_slots='pg_conflict_detection';
+ERROR: invalid value for parameter "synchronized_standby_slots": "pg_conflict_detection"
+DETAIL: replication slot name "pg_conflict_detection" is reserved
+HINT: The name "pg_conflict_detection" is reserved for the conflict detection slot.
+-- Cannot set synchronized_standby_slots to a invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+ERROR: invalid value for parameter "synchronized_standby_slots": "invalid*"
+DETAIL: replication slot name "invalid*" contains invalid character
+HINT: Replication slot names may only contain lower case letters, numbers, and the underscore character.
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+SELECT pg_reload_conf();
+ pg_reload_conf
+----------------
+ t
+(1 row)
+
+-- Parallel worker does not throw error during startup.
+SET min_parallel_table_scan_size TO 0;
+SET max_parallel_workers_per_gather TO 2;
+SET parallel_setup_cost TO 0;
+SET parallel_tuple_cost TO 0;
+CREATE TABLE t1(a int);
+INSERT INTO t1 VALUES(1), (2), (3), (4);
+SELECT count(*) FROM t1;
+ count
+-------
+ 4
+(1 row)
+
diff --git a/src/test/regress/sql/guc.sql b/src/test/regress/sql/guc.sql
index f65f84a2632..45a3e3ecec7 100644
--- a/src/test/regress/sql/guc.sql
+++ b/src/test/regress/sql/guc.sql
@@ -368,3 +368,23 @@ SELECT name FROM tab_settings_flags
WHERE no_reset AND NOT no_reset_all
ORDER BY 1;
DROP TABLE tab_settings_flags;
+
+-- Test for GUC synchronized standby slots
+-- Cannot set synchronized_standby_slots to a reserved slot name.
+ALTER SYSTEM SET synchronized_standby_slots='pg_conflict_detection';
+
+-- Cannot set synchronized_standby_slots to a invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+SELECT pg_reload_conf();
+
+-- Parallel worker does not throw error during startup.
+SET min_parallel_table_scan_size TO 0;
+SET max_parallel_workers_per_gather TO 2;
+SET parallel_setup_cost TO 0;
+SET parallel_tuple_cost TO 0;
+CREATE TABLE t1(a int);
+INSERT INTO t1 VALUES(1), (2), (3), (4);
+SELECT count(*) FROM t1;
--
2.34.1
v7_REL_18-0001-Remove-the-validation-from-the-GUC-check-h.txttext/plain; charset=US-ASCII; name=v7_REL_18-0001-Remove-the-validation-from-the-GUC-check-h.txtDownload
From 69d56babde73082dc53398fb25a6a60639fdbbb1 Mon Sep 17 00:00:00 2001
From: Shlok Kyal <shlok.kyal.oss@gmail.com>
Date: Wed, 10 Sep 2025 15:08:23 +0530
Subject: [PATCH v7_REL_18] Remove the validation from the GUC check hook and
add parsing check
The validation in check_synchronized_standby_slots cannot be run
in postmaster and hence can result inconsistent values in some
backends that inherit the value from postmaster and those
that are started newly. Also, this validation results in parallel
workers fail to with error. This causes all the commands run by
parallel workers to fail, which seems unnecesary. This validation
already happens in StandbySlotsHaveCaughtup() where this GUC is
used, so it can be removed from the GUC check. Also added a
parsing check for the slot names specified in this GUC.
---
src/backend/replication/slot.c | 59 +++++++++----------------------
src/test/regress/expected/guc.out | 27 ++++++++++++++
src/test/regress/sql/guc.sql | 17 +++++++++
3 files changed, 60 insertions(+), 43 deletions(-)
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index ac910f6a74a..101157ed8c9 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -2743,53 +2743,32 @@ GetSlotInvalidationCauseName(ReplicationSlotInvalidationCause cause)
static bool
validate_sync_standby_slots(char *rawname, List **elemlist)
{
- bool ok;
-
/* Verify syntax and parse string into a list of identifiers */
- ok = SplitIdentifierString(rawname, ',', elemlist);
-
- if (!ok)
+ if (!SplitIdentifierString(rawname, ',', elemlist))
{
GUC_check_errdetail("List syntax is invalid.");
+ return false;
}
- else if (MyProc)
+
+ /* Iterate the list to validate each slot name */
+ foreach_ptr(char, name, *elemlist)
{
- /*
- * Check that each specified slot exist and is physical.
- *
- * Because we need an LWLock, we cannot do this on processes without a
- * PGPROC, so we skip it there; but see comments in
- * StandbySlotsHaveCaughtup() as to why that's not a problem.
- */
- LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
+ int err_code;
+ char *err_msg = NULL;
+ char *err_hint = NULL;
- foreach_ptr(char, name, *elemlist)
+ if (!ReplicationSlotValidateNameInternal(name, &err_code, &err_msg,
+ &err_hint))
{
- ReplicationSlot *slot;
-
- slot = SearchNamedReplicationSlot(name, false);
-
- if (!slot)
- {
- GUC_check_errdetail("Replication slot \"%s\" does not exist.",
- name);
- ok = false;
- break;
- }
-
- if (!SlotIsPhysical(slot))
- {
- GUC_check_errdetail("\"%s\" is not a physical replication slot.",
- name);
- ok = false;
- break;
- }
+ GUC_check_errcode(err_code);
+ GUC_check_errdetail("%s", err_msg);
+ if (err_hint != NULL)
+ GUC_check_errhint("%s", err_hint);
+ return false;
}
-
- LWLockRelease(ReplicationSlotControlLock);
}
- return ok;
+ return true;
}
/*
@@ -2947,12 +2926,6 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
/*
* If a slot name provided in synchronized_standby_slots does not
* exist, report a message and exit the loop.
- *
- * Though validate_sync_standby_slots (the GUC check_hook) tries to
- * avoid this, it can nonetheless happen because the user can specify
- * a nonexistent slot name before server startup. That function cannot
- * validate such a slot during startup, as ReplicationSlotCtl is not
- * initialized by then. Also, the user might have dropped one slot.
*/
if (!slot)
{
diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out
index 7f9e29c765c..12a5b7bc7cc 100644
--- a/src/test/regress/expected/guc.out
+++ b/src/test/regress/expected/guc.out
@@ -913,3 +913,30 @@ SELECT name FROM tab_settings_flags
(0 rows)
DROP TABLE tab_settings_flags;
+-- Test for GUC synchronized standby slots
+-- Cannot set synchronized_standby_slots to a invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+ERROR: invalid value for parameter "synchronized_standby_slots": "invalid*"
+DETAIL: replication slot name "invalid*" contains invalid character
+HINT: Replication slot names may only contain lower case letters, numbers, and the underscore character.
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+SELECT pg_reload_conf();
+ pg_reload_conf
+----------------
+ t
+(1 row)
+
+-- Parallel worker does not throw error during startup.
+SET min_parallel_table_scan_size TO 0;
+SET max_parallel_workers_per_gather TO 2;
+SET parallel_setup_cost TO 0;
+SET parallel_tuple_cost TO 0;
+CREATE TABLE t1(a int);
+INSERT INTO t1 VALUES(1), (2), (3), (4);
+SELECT count(*) FROM t1;
+ count
+-------
+ 4
+(1 row)
+
diff --git a/src/test/regress/sql/guc.sql b/src/test/regress/sql/guc.sql
index f65f84a2632..1b22e2aa26f 100644
--- a/src/test/regress/sql/guc.sql
+++ b/src/test/regress/sql/guc.sql
@@ -368,3 +368,20 @@ SELECT name FROM tab_settings_flags
WHERE no_reset AND NOT no_reset_all
ORDER BY 1;
DROP TABLE tab_settings_flags;
+
+-- Test for GUC synchronized standby slots
+-- Cannot set synchronized_standby_slots to a invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+SELECT pg_reload_conf();
+
+-- Parallel worker does not throw error during startup.
+SET min_parallel_table_scan_size TO 0;
+SET max_parallel_workers_per_gather TO 2;
+SET parallel_setup_cost TO 0;
+SET parallel_tuple_cost TO 0;
+CREATE TABLE t1(a int);
+INSERT INTO t1 VALUES(1), (2), (3), (4);
+SELECT count(*) FROM t1;
--
2.34.1
On Thu, Oct 23, 2025 at 2:58 PM Shlok Kyal <shlok.kyal.oss@gmail.com> wrote:
On Thu, 23 Oct 2025 at 13:45, Hayato Kuroda (Fujitsu)
<kuroda.hayato@fujitsu.com> wrote:2.
Also, test for PG18 should not have the case which rejects the reserved name.
Why to have that even for HEAD and PG18?
3.
```
-- Parallel worker does not throw error during startup.
SET min_parallel_table_scan_size TO 0;
SET parallel_setup_cost TO 0;
SET parallel_tuple_cost TO 0;
```According to contrib/pg_stat_statements/sql/parallel.sql, max_parallel_workers_per_gather
should be also set. There is a possiblity that `make installcheck` is used and
it has max_parallel_workers_per_gather=0.
+-- Parallel worker does not throw error during startup.
+SET min_parallel_table_scan_size TO 0;
+SET max_parallel_workers_per_gather TO 2;
+SET parallel_setup_cost TO 0;
+SET parallel_tuple_cost TO 0;
+CREATE TABLE t1(a int);
+INSERT INTO t1 VALUES(1), (2), (3), (4);
+SELECT count(*) FROM t1;
Isn't it better to reset these parameters after the test?
--
With Regards,
Amit Kapila.
On Thu, Oct 23, 2025 at 8:28 PM Amit Kapila <amit.kapila16@gmail.com> wrote:
+-- Parallel worker does not throw error during startup. +SET min_parallel_table_scan_size TO 0; +SET max_parallel_workers_per_gather TO 2; +SET parallel_setup_cost TO 0; +SET parallel_tuple_cost TO 0; +CREATE TABLE t1(a int); +INSERT INTO t1 VALUES(1), (2), (3), (4); +SELECT count(*) FROM t1;Isn't it better to reset these parameters after the test?
I think the intention of this test case is to verify that the issue seen
in HEAD no longer occurs with the patch applied. So in HEAD this test
procedure needs to be able to reproduce the problem with
synchronized_standby_slots and parallel workers, but does it actually do?
I'm afraid additional steps are needed.
Also, I wonder if it's really worth doing this test after the fix,
since it seems a special case.
+-- Cannot set synchronized_standby_slots to a invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
Typo: "a invalid" should be "an invalid"
Regards,
--
Fujii Masao
On Thu, Oct 23, 2025 at 9:08 PM Fujii Masao <masao.fujii@gmail.com> wrote:
On Thu, Oct 23, 2025 at 8:28 PM Amit Kapila <amit.kapila16@gmail.com> wrote:
+-- Parallel worker does not throw error during startup. +SET min_parallel_table_scan_size TO 0; +SET max_parallel_workers_per_gather TO 2; +SET parallel_setup_cost TO 0; +SET parallel_tuple_cost TO 0; +CREATE TABLE t1(a int); +INSERT INTO t1 VALUES(1), (2), (3), (4); +SELECT count(*) FROM t1;Isn't it better to reset these parameters after the test?
I think the intention of this test case is to verify that the issue seen
in HEAD no longer occurs with the patch applied. So in HEAD this test
procedure needs to be able to reproduce the problem with
synchronized_standby_slots and parallel workers, but does it actually do?
I'm afraid additional steps are needed.Also, I wonder if it's really worth doing this test after the fix,
since it seems a special case.
Agreed. I also don't see the need.
+-- Cannot set synchronized_standby_slots to a invalid slot name. +ALTER SYSTEM SET synchronized_standby_slots='invalid*';Typo: "a invalid" should be "an invalid"
We can keep this test as the results with and without patch will be
different for this case.
HEAD:
postgres=# ALTER SYSTEM SET synchronized_standby_slots='invalid*';
ERROR: invalid value for parameter "synchronized_standby_slots": "invalid*"
DETAIL: Replication slot "invalid*" does not exist.
Patch:
postgres=# ALTER SYSTEM SET synchronized_standby_slots='invalid*';
ERROR: invalid value for parameter "synchronized_standby_slots": "invalid*"
DETAIL: replication slot name "invalid*" contains invalid character
HINT: Replication slot names may only contain lower case letters,
numbers, and the underscore character.
--
With Regards,
Amit Kapila.
Hi Amit,
Thanks for reviewing the patch.
On Thu, 23 Oct 2025 at 16:58, Amit Kapila <amit.kapila16@gmail.com> wrote:
On Thu, Oct 23, 2025 at 2:58 PM Shlok Kyal <shlok.kyal.oss@gmail.com> wrote:
On Thu, 23 Oct 2025 at 13:45, Hayato Kuroda (Fujitsu)
<kuroda.hayato@fujitsu.com> wrote:2.
Also, test for PG18 should not have the case which rejects the reserved name.Why to have that even for HEAD and PG18?
I added it as per comment in [1]/messages/by-id/CAE9k0P=OFMFCRy9aDGWZ3bt91tbB1WnzsAbzXN72iWBaGVuMrw@mail.gmail.com to increase test coverage. I also do
not see any other existing test in HEAD hitting this error. So I added
this test.
3.
```
-- Parallel worker does not throw error during startup.
SET min_parallel_table_scan_size TO 0;
SET parallel_setup_cost TO 0;
SET parallel_tuple_cost TO 0;
```According to contrib/pg_stat_statements/sql/parallel.sql, max_parallel_workers_per_gather
should be also set. There is a possiblity that `make installcheck` is used and
it has max_parallel_workers_per_gather=0.+-- Parallel worker does not throw error during startup. +SET min_parallel_table_scan_size TO 0; +SET max_parallel_workers_per_gather TO 2; +SET parallel_setup_cost TO 0; +SET parallel_tuple_cost TO 0; +CREATE TABLE t1(a int); +INSERT INTO t1 VALUES(1), (2), (3), (4); +SELECT count(*) FROM t1;Isn't it better to reset these parameters after the test?
According to the latest discussion. I have removed this test.
Attached the updated patches.
[1]: /messages/by-id/CAE9k0P=OFMFCRy9aDGWZ3bt91tbB1WnzsAbzXN72iWBaGVuMrw@mail.gmail.com
Thanks,
Shlok Kyal
Attachments:
v8_REL_17-0001-Remove-the-validation-from-the-GUC-check-h.txttext/plain; charset=US-ASCII; name=v8_REL_17-0001-Remove-the-validation-from-the-GUC-check-h.txtDownload
From 628373744030d102d41391c2838d3ab4a15bd343 Mon Sep 17 00:00:00 2001
From: Shlok Kyal <shlok.kyal.oss@gmail.com>
Date: Thu, 23 Oct 2025 11:09:47 +0530
Subject: [PATCH v8_REL_17] Remove the validation from the GUC check hook and
add parsing check
The validation in check_synchronized_standby_slots cannot be run
in postmaster and hence can result inconsistent values in some
backends that inherit the value from postmaster and those
that are started newly. Also, this validation results in parallel
workers fail to with error. This causes all the commands run by
parallel workers to fail, which seems unnecesary. This validation
already happens in StandbySlotsHaveCaughtup() where this GUC is
used, so it can be removed from the GUC check. Also added a
parsing check for the slot names specified in this GUC.
---
src/backend/replication/slot.c | 59 +++++++++----------------------
src/test/regress/expected/guc.out | 22 ++++++++++++
src/test/regress/sql/guc.sql | 12 +++++++
3 files changed, 50 insertions(+), 43 deletions(-)
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 80b8abde3a2..4bc2be33396 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -2468,53 +2468,32 @@ GetSlotInvalidationCause(const char *invalidation_reason)
static bool
validate_sync_standby_slots(char *rawname, List **elemlist)
{
- bool ok;
-
/* Verify syntax and parse string into a list of identifiers */
- ok = SplitIdentifierString(rawname, ',', elemlist);
-
- if (!ok)
+ if (!SplitIdentifierString(rawname, ',', elemlist))
{
GUC_check_errdetail("List syntax is invalid.");
+ return false;
}
- else if (MyProc)
+
+ /* Iterate the list to validate each slot name */
+ foreach_ptr(char, name, *elemlist)
{
- /*
- * Check that each specified slot exist and is physical.
- *
- * Because we need an LWLock, we cannot do this on processes without a
- * PGPROC, so we skip it there; but see comments in
- * StandbySlotsHaveCaughtup() as to why that's not a problem.
- */
- LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
+ int err_code;
+ char *err_msg = NULL;
+ char *err_hint = NULL;
- foreach_ptr(char, name, *elemlist)
+ if (!ReplicationSlotValidateNameInternal(name, &err_code, &err_msg,
+ &err_hint))
{
- ReplicationSlot *slot;
-
- slot = SearchNamedReplicationSlot(name, false);
-
- if (!slot)
- {
- GUC_check_errdetail("replication slot \"%s\" does not exist",
- name);
- ok = false;
- break;
- }
-
- if (!SlotIsPhysical(slot))
- {
- GUC_check_errdetail("\"%s\" is not a physical replication slot",
- name);
- ok = false;
- break;
- }
+ GUC_check_errcode(err_code);
+ GUC_check_errdetail("%s", err_msg);
+ if (err_hint != NULL)
+ GUC_check_errhint("%s", err_hint);
+ return false;
}
-
- LWLockRelease(ReplicationSlotControlLock);
}
- return ok;
+ return true;
}
/*
@@ -2672,12 +2651,6 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
/*
* If a slot name provided in synchronized_standby_slots does not
* exist, report a message and exit the loop.
- *
- * Though validate_sync_standby_slots (the GUC check_hook) tries to
- * avoid this, it can nonetheless happen because the user can specify
- * a nonexistent slot name before server startup. That function cannot
- * validate such a slot during startup, as ReplicationSlotCtl is not
- * initialized by then. Also, the user might have dropped one slot.
*/
if (!slot)
{
diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out
index 455b6d6c0ce..f6bf9238b4a 100644
--- a/src/test/regress/expected/guc.out
+++ b/src/test/regress/expected/guc.out
@@ -888,3 +888,25 @@ SELECT name FROM tab_settings_flags
(0 rows)
DROP TABLE tab_settings_flags;
+-- Test for GUC synchronized standby slots.
+-- Cannot set synchronized_standby_slots to an invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+ERROR: invalid value for parameter "synchronized_standby_slots": "invalid*"
+DETAIL: replication slot name "invalid*" contains invalid character
+HINT: Replication slot names may only contain lower case letters, numbers, and the underscore character.
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+SELECT pg_reload_conf();
+ pg_reload_conf
+----------------
+ t
+(1 row)
+
+-- Reset the GUC.
+ALTER SYSTEM RESET synchronized_standby_slots;
+SELECT pg_reload_conf();
+ pg_reload_conf
+----------------
+ t
+(1 row)
+
diff --git a/src/test/regress/sql/guc.sql b/src/test/regress/sql/guc.sql
index dc79761955d..5a2b6ed596c 100644
--- a/src/test/regress/sql/guc.sql
+++ b/src/test/regress/sql/guc.sql
@@ -353,3 +353,15 @@ SELECT name FROM tab_settings_flags
WHERE no_reset AND NOT no_reset_all
ORDER BY 1;
DROP TABLE tab_settings_flags;
+
+-- Test for GUC synchronized standby slots.
+-- Cannot set synchronized_standby_slots to an invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+SELECT pg_reload_conf();
+
+-- Reset the GUC.
+ALTER SYSTEM RESET synchronized_standby_slots;
+SELECT pg_reload_conf();
--
2.34.1
v8_REL_18-0001-Remove-the-validation-from-the-GUC-check-h.txttext/plain; charset=US-ASCII; name=v8_REL_18-0001-Remove-the-validation-from-the-GUC-check-h.txtDownload
From b29d4c75463d2b8fafb4a3cc656156b5abf7194d Mon Sep 17 00:00:00 2001
From: Shlok Kyal <shlok.kyal.oss@gmail.com>
Date: Wed, 10 Sep 2025 15:08:23 +0530
Subject: [PATCH v8_REL_18] Remove the validation from the GUC check hook and
add parsing check
The validation in check_synchronized_standby_slots cannot be run
in postmaster and hence can result inconsistent values in some
backends that inherit the value from postmaster and those
that are started newly. Also, this validation results in parallel
workers fail to with error. This causes all the commands run by
parallel workers to fail, which seems unnecesary. This validation
already happens in StandbySlotsHaveCaughtup() where this GUC is
used, so it can be removed from the GUC check. Also added a
parsing check for the slot names specified in this GUC.
---
src/backend/replication/slot.c | 59 +++++++++----------------------
src/test/regress/expected/guc.out | 22 ++++++++++++
src/test/regress/sql/guc.sql | 12 +++++++
3 files changed, 50 insertions(+), 43 deletions(-)
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index ac910f6a74a..101157ed8c9 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -2743,53 +2743,32 @@ GetSlotInvalidationCauseName(ReplicationSlotInvalidationCause cause)
static bool
validate_sync_standby_slots(char *rawname, List **elemlist)
{
- bool ok;
-
/* Verify syntax and parse string into a list of identifiers */
- ok = SplitIdentifierString(rawname, ',', elemlist);
-
- if (!ok)
+ if (!SplitIdentifierString(rawname, ',', elemlist))
{
GUC_check_errdetail("List syntax is invalid.");
+ return false;
}
- else if (MyProc)
+
+ /* Iterate the list to validate each slot name */
+ foreach_ptr(char, name, *elemlist)
{
- /*
- * Check that each specified slot exist and is physical.
- *
- * Because we need an LWLock, we cannot do this on processes without a
- * PGPROC, so we skip it there; but see comments in
- * StandbySlotsHaveCaughtup() as to why that's not a problem.
- */
- LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
+ int err_code;
+ char *err_msg = NULL;
+ char *err_hint = NULL;
- foreach_ptr(char, name, *elemlist)
+ if (!ReplicationSlotValidateNameInternal(name, &err_code, &err_msg,
+ &err_hint))
{
- ReplicationSlot *slot;
-
- slot = SearchNamedReplicationSlot(name, false);
-
- if (!slot)
- {
- GUC_check_errdetail("Replication slot \"%s\" does not exist.",
- name);
- ok = false;
- break;
- }
-
- if (!SlotIsPhysical(slot))
- {
- GUC_check_errdetail("\"%s\" is not a physical replication slot.",
- name);
- ok = false;
- break;
- }
+ GUC_check_errcode(err_code);
+ GUC_check_errdetail("%s", err_msg);
+ if (err_hint != NULL)
+ GUC_check_errhint("%s", err_hint);
+ return false;
}
-
- LWLockRelease(ReplicationSlotControlLock);
}
- return ok;
+ return true;
}
/*
@@ -2947,12 +2926,6 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
/*
* If a slot name provided in synchronized_standby_slots does not
* exist, report a message and exit the loop.
- *
- * Though validate_sync_standby_slots (the GUC check_hook) tries to
- * avoid this, it can nonetheless happen because the user can specify
- * a nonexistent slot name before server startup. That function cannot
- * validate such a slot during startup, as ReplicationSlotCtl is not
- * initialized by then. Also, the user might have dropped one slot.
*/
if (!slot)
{
diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out
index 7f9e29c765c..6e9a635647d 100644
--- a/src/test/regress/expected/guc.out
+++ b/src/test/regress/expected/guc.out
@@ -913,3 +913,25 @@ SELECT name FROM tab_settings_flags
(0 rows)
DROP TABLE tab_settings_flags;
+-- Test for GUC synchronized standby slots.
+-- Cannot set synchronized_standby_slots to an invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+ERROR: invalid value for parameter "synchronized_standby_slots": "invalid*"
+DETAIL: replication slot name "invalid*" contains invalid character
+HINT: Replication slot names may only contain lower case letters, numbers, and the underscore character.
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+SELECT pg_reload_conf();
+ pg_reload_conf
+----------------
+ t
+(1 row)
+
+-- Reset the GUC.
+ALTER SYSTEM RESET synchronized_standby_slots;
+SELECT pg_reload_conf();
+ pg_reload_conf
+----------------
+ t
+(1 row)
+
diff --git a/src/test/regress/sql/guc.sql b/src/test/regress/sql/guc.sql
index f65f84a2632..1f3324932c2 100644
--- a/src/test/regress/sql/guc.sql
+++ b/src/test/regress/sql/guc.sql
@@ -368,3 +368,15 @@ SELECT name FROM tab_settings_flags
WHERE no_reset AND NOT no_reset_all
ORDER BY 1;
DROP TABLE tab_settings_flags;
+
+-- Test for GUC synchronized standby slots.
+-- Cannot set synchronized_standby_slots to an invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+SELECT pg_reload_conf();
+
+-- Reset the GUC.
+ALTER SYSTEM RESET synchronized_standby_slots;
+SELECT pg_reload_conf();
--
2.34.1
v8_HEAD-0001-Remove-the-validation-from-the-GUC-check-hoo.patchapplication/octet-stream; name=v8_HEAD-0001-Remove-the-validation-from-the-GUC-check-hoo.patchDownload
From a1c241da44a1bda396488a7bd0d22c2eac796eec Mon Sep 17 00:00:00 2001
From: Shlok Kyal <shlok.kyal.oss@gmail.com>
Date: Wed, 10 Sep 2025 15:08:23 +0530
Subject: [PATCH v8_HEAD] Remove the validation from the GUC check hook and add
parsing check
The validation in check_synchronized_standby_slots cannot be run
in postmaster and hence can result inconsistent values in some
backends that inherit the value from postmaster and those
that are started newly. Also, this validation results in parallel
workers fail to with error. This causes all the commands run by
parallel workers to fail, which seems unnecesary. This validation
already happens in StandbySlotsHaveCaughtup() where this GUC is
used, so it can be removed from the GUC check. Also added a
parsing check for the slot names specified in this GUC.
---
src/backend/replication/slot.c | 59 +++++++++----------------------
src/test/regress/expected/guc.out | 27 ++++++++++++++
src/test/regress/sql/guc.sql | 15 ++++++++
3 files changed, 58 insertions(+), 43 deletions(-)
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index a4ca363f20d..1e9f4602c69 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -2784,53 +2784,32 @@ GetSlotInvalidationCauseName(ReplicationSlotInvalidationCause cause)
static bool
validate_sync_standby_slots(char *rawname, List **elemlist)
{
- bool ok;
-
/* Verify syntax and parse string into a list of identifiers */
- ok = SplitIdentifierString(rawname, ',', elemlist);
-
- if (!ok)
+ if (!SplitIdentifierString(rawname, ',', elemlist))
{
GUC_check_errdetail("List syntax is invalid.");
+ return false;
}
- else if (MyProc)
+
+ /* Iterate the list to validate each slot name */
+ foreach_ptr(char, name, *elemlist)
{
- /*
- * Check that each specified slot exist and is physical.
- *
- * Because we need an LWLock, we cannot do this on processes without a
- * PGPROC, so we skip it there; but see comments in
- * StandbySlotsHaveCaughtup() as to why that's not a problem.
- */
- LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
+ int err_code;
+ char *err_msg = NULL;
+ char *err_hint = NULL;
- foreach_ptr(char, name, *elemlist)
+ if (!ReplicationSlotValidateNameInternal(name, false, &err_code,
+ &err_msg, &err_hint))
{
- ReplicationSlot *slot;
-
- slot = SearchNamedReplicationSlot(name, false);
-
- if (!slot)
- {
- GUC_check_errdetail("Replication slot \"%s\" does not exist.",
- name);
- ok = false;
- break;
- }
-
- if (!SlotIsPhysical(slot))
- {
- GUC_check_errdetail("\"%s\" is not a physical replication slot.",
- name);
- ok = false;
- break;
- }
+ GUC_check_errcode(err_code);
+ GUC_check_errdetail("%s", err_msg);
+ if (err_hint != NULL)
+ GUC_check_errhint("%s", err_hint);
+ return false;
}
-
- LWLockRelease(ReplicationSlotControlLock);
}
- return ok;
+ return true;
}
/*
@@ -2988,12 +2967,6 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
/*
* If a slot name provided in synchronized_standby_slots does not
* exist, report a message and exit the loop.
- *
- * Though validate_sync_standby_slots (the GUC check_hook) tries to
- * avoid this, it can nonetheless happen because the user can specify
- * a nonexistent slot name before server startup. That function cannot
- * validate such a slot during startup, as ReplicationSlotCtl is not
- * initialized by then. Also, the user might have dropped one slot.
*/
if (!slot)
{
diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out
index 7f9e29c765c..853ed4f7d89 100644
--- a/src/test/regress/expected/guc.out
+++ b/src/test/regress/expected/guc.out
@@ -913,3 +913,30 @@ SELECT name FROM tab_settings_flags
(0 rows)
DROP TABLE tab_settings_flags;
+-- Test for GUC synchronized standby slots.
+-- Cannot set synchronized_standby_slots to a reserved slot name.
+ALTER SYSTEM SET synchronized_standby_slots='pg_conflict_detection';
+ERROR: invalid value for parameter "synchronized_standby_slots": "pg_conflict_detection"
+DETAIL: replication slot name "pg_conflict_detection" is reserved
+HINT: The name "pg_conflict_detection" is reserved for the conflict detection slot.
+-- Cannot set synchronized_standby_slots to an invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+ERROR: invalid value for parameter "synchronized_standby_slots": "invalid*"
+DETAIL: replication slot name "invalid*" contains invalid character
+HINT: Replication slot names may only contain lower case letters, numbers, and the underscore character.
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+SELECT pg_reload_conf();
+ pg_reload_conf
+----------------
+ t
+(1 row)
+
+-- Reset the GUC.
+ALTER SYSTEM RESET synchronized_standby_slots;
+SELECT pg_reload_conf();
+ pg_reload_conf
+----------------
+ t
+(1 row)
+
diff --git a/src/test/regress/sql/guc.sql b/src/test/regress/sql/guc.sql
index f65f84a2632..6e566102e0e 100644
--- a/src/test/regress/sql/guc.sql
+++ b/src/test/regress/sql/guc.sql
@@ -368,3 +368,18 @@ SELECT name FROM tab_settings_flags
WHERE no_reset AND NOT no_reset_all
ORDER BY 1;
DROP TABLE tab_settings_flags;
+
+-- Test for GUC synchronized standby slots.
+-- Cannot set synchronized_standby_slots to a reserved slot name.
+ALTER SYSTEM SET synchronized_standby_slots='pg_conflict_detection';
+
+-- Cannot set synchronized_standby_slots to an invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+SELECT pg_reload_conf();
+
+-- Reset the GUC.
+ALTER SYSTEM RESET synchronized_standby_slots;
+SELECT pg_reload_conf();
--
2.34.1
Hi Fujii-san, Amit,
Thanks for reviewing the patch.
On Fri, 24 Oct 2025 at 10:31, Amit Kapila <amit.kapila16@gmail.com> wrote:
On Thu, Oct 23, 2025 at 9:08 PM Fujii Masao <masao.fujii@gmail.com> wrote:
On Thu, Oct 23, 2025 at 8:28 PM Amit Kapila <amit.kapila16@gmail.com> wrote:
+-- Parallel worker does not throw error during startup. +SET min_parallel_table_scan_size TO 0; +SET max_parallel_workers_per_gather TO 2; +SET parallel_setup_cost TO 0; +SET parallel_tuple_cost TO 0; +CREATE TABLE t1(a int); +INSERT INTO t1 VALUES(1), (2), (3), (4); +SELECT count(*) FROM t1;Isn't it better to reset these parameters after the test?
I think the intention of this test case is to verify that the issue seen
in HEAD no longer occurs with the patch applied. So in HEAD this test
procedure needs to be able to reproduce the problem with
synchronized_standby_slots and parallel workers, but does it actually do?
I'm afraid additional steps are needed.Also, I wonder if it's really worth doing this test after the fix,
since it seems a special case.Agreed. I also don't see the need.
I also agree. I have removed the test in the latest version of patch.
+-- Cannot set synchronized_standby_slots to a invalid slot name. +ALTER SYSTEM SET synchronized_standby_slots='invalid*';Typo: "a invalid" should be "an invalid"
We can keep this test as the results with and without patch will be
different for this case.HEAD:
postgres=# ALTER SYSTEM SET synchronized_standby_slots='invalid*';
ERROR: invalid value for parameter "synchronized_standby_slots": "invalid*"
DETAIL: Replication slot "invalid*" does not exist.Patch:
postgres=# ALTER SYSTEM SET synchronized_standby_slots='invalid*';
ERROR: invalid value for parameter "synchronized_standby_slots": "invalid*"
DETAIL: replication slot name "invalid*" contains invalid character
HINT: Replication slot names may only contain lower case letters,
numbers, and the underscore character.
I have corrected the typo in the comment and also kept this test.
I have attached the patches in [1]/messages/by-id/CANhcyEXBnQs31N2zAH7m9uSNWfOBianZEMEAzi-rj_kQ3B9ihQ@mail.gmail.com.
[1]: /messages/by-id/CANhcyEXBnQs31N2zAH7m9uSNWfOBianZEMEAzi-rj_kQ3B9ihQ@mail.gmail.com
Thanks,
Shlok Kyal
Dear Shlok,
```
-- Can set synchronized_standby_slots to a non-existent slot name.
ALTER SYSTEM SET synchronized_standby_slots='missing';
SELECT pg_reload_conf();
-- Reset the GUC.
ALTER SYSTEM RESET synchronized_standby_slots;
SELECT pg_reload_conf();
```
pg_reload_conf() is called twice here but I'm not sure it is really needed.
ALTER SYSTEM itself can validate parameters via parse_and_validate_value(elevel=ERROR),
and pg_reload_conf() won't affect synchronously. Also, the backend won't output
even if the parameter is invalid.
Best regards,
Hayato Kuroda
FUJITSU LIMITED
On Fri, Oct 24, 2025 at 1:24 PM Hayato Kuroda (Fujitsu)
<kuroda.hayato@fujitsu.com> wrote:
Dear Shlok,
```
-- Can set synchronized_standby_slots to a non-existent slot name.
ALTER SYSTEM SET synchronized_standby_slots='missing';
SELECT pg_reload_conf();-- Reset the GUC.
ALTER SYSTEM RESET synchronized_standby_slots;
SELECT pg_reload_conf();
```pg_reload_conf() is called twice here but I'm not sure it is really needed.
ALTER SYSTEM itself can validate parameters via parse_and_validate_value(elevel=ERROR),
and pg_reload_conf() won't affect synchronously.
I also think pg_reload_conf() won't be required here.
--
With Regards,
Amit Kapila.
On Fri, 24 Oct 2025 at 15:08, Amit Kapila <amit.kapila16@gmail.com> wrote:
On Fri, Oct 24, 2025 at 1:24 PM Hayato Kuroda (Fujitsu)
<kuroda.hayato@fujitsu.com> wrote:Dear Shlok,
```
-- Can set synchronized_standby_slots to a non-existent slot name.
ALTER SYSTEM SET synchronized_standby_slots='missing';
SELECT pg_reload_conf();-- Reset the GUC.
ALTER SYSTEM RESET synchronized_standby_slots;
SELECT pg_reload_conf();
```pg_reload_conf() is called twice here but I'm not sure it is really needed.
ALTER SYSTEM itself can validate parameters via parse_and_validate_value(elevel=ERROR),
and pg_reload_conf() won't affect synchronously.I also think pg_reload_conf() won't be required here.
I agree that .pg_reload_conf() is not required. I have removed it in
the latest version of patches.
Thanks,
Shlok Kyal
Attachments:
v9_REL_18-0001-Remove-the-validation-from-the-GUC-check-h.txttext/plain; charset=US-ASCII; name=v9_REL_18-0001-Remove-the-validation-from-the-GUC-check-h.txtDownload
From 789534c514a3c587c9f9d8dfb20bab1d361d0eb3 Mon Sep 17 00:00:00 2001
From: Shlok Kyal <shlok.kyal.oss@gmail.com>
Date: Wed, 10 Sep 2025 15:08:23 +0530
Subject: [PATCH v9_REL_18] Remove the validation from the GUC check hook and
add parsing check
The validation in check_synchronized_standby_slots cannot be run
in postmaster and hence can result inconsistent values in some
backends that inherit the value from postmaster and those
that are started newly. Also, this validation results in parallel
workers fail to with error. This causes all the commands run by
parallel workers to fail, which seems unnecesary. This validation
already happens in StandbySlotsHaveCaughtup() where this GUC is
used, so it can be removed from the GUC check. Also added a
parsing check for the slot names specified in this GUC.
---
src/backend/replication/slot.c | 59 +++++++++----------------------
src/test/regress/expected/guc.out | 10 ++++++
src/test/regress/sql/guc.sql | 10 ++++++
3 files changed, 36 insertions(+), 43 deletions(-)
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index ac910f6a74a..101157ed8c9 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -2743,53 +2743,32 @@ GetSlotInvalidationCauseName(ReplicationSlotInvalidationCause cause)
static bool
validate_sync_standby_slots(char *rawname, List **elemlist)
{
- bool ok;
-
/* Verify syntax and parse string into a list of identifiers */
- ok = SplitIdentifierString(rawname, ',', elemlist);
-
- if (!ok)
+ if (!SplitIdentifierString(rawname, ',', elemlist))
{
GUC_check_errdetail("List syntax is invalid.");
+ return false;
}
- else if (MyProc)
+
+ /* Iterate the list to validate each slot name */
+ foreach_ptr(char, name, *elemlist)
{
- /*
- * Check that each specified slot exist and is physical.
- *
- * Because we need an LWLock, we cannot do this on processes without a
- * PGPROC, so we skip it there; but see comments in
- * StandbySlotsHaveCaughtup() as to why that's not a problem.
- */
- LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
+ int err_code;
+ char *err_msg = NULL;
+ char *err_hint = NULL;
- foreach_ptr(char, name, *elemlist)
+ if (!ReplicationSlotValidateNameInternal(name, &err_code, &err_msg,
+ &err_hint))
{
- ReplicationSlot *slot;
-
- slot = SearchNamedReplicationSlot(name, false);
-
- if (!slot)
- {
- GUC_check_errdetail("Replication slot \"%s\" does not exist.",
- name);
- ok = false;
- break;
- }
-
- if (!SlotIsPhysical(slot))
- {
- GUC_check_errdetail("\"%s\" is not a physical replication slot.",
- name);
- ok = false;
- break;
- }
+ GUC_check_errcode(err_code);
+ GUC_check_errdetail("%s", err_msg);
+ if (err_hint != NULL)
+ GUC_check_errhint("%s", err_hint);
+ return false;
}
-
- LWLockRelease(ReplicationSlotControlLock);
}
- return ok;
+ return true;
}
/*
@@ -2947,12 +2926,6 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
/*
* If a slot name provided in synchronized_standby_slots does not
* exist, report a message and exit the loop.
- *
- * Though validate_sync_standby_slots (the GUC check_hook) tries to
- * avoid this, it can nonetheless happen because the user can specify
- * a nonexistent slot name before server startup. That function cannot
- * validate such a slot during startup, as ReplicationSlotCtl is not
- * initialized by then. Also, the user might have dropped one slot.
*/
if (!slot)
{
diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out
index 7f9e29c765c..804bf17f360 100644
--- a/src/test/regress/expected/guc.out
+++ b/src/test/regress/expected/guc.out
@@ -913,3 +913,13 @@ SELECT name FROM tab_settings_flags
(0 rows)
DROP TABLE tab_settings_flags;
+-- Test for GUC synchronized standby slots.
+-- Cannot set synchronized_standby_slots to an invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+ERROR: invalid value for parameter "synchronized_standby_slots": "invalid*"
+DETAIL: replication slot name "invalid*" contains invalid character
+HINT: Replication slot names may only contain lower case letters, numbers, and the underscore character.
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+-- Reset the GUC.
+ALTER SYSTEM RESET synchronized_standby_slots;
diff --git a/src/test/regress/sql/guc.sql b/src/test/regress/sql/guc.sql
index f65f84a2632..10b790b2c5b 100644
--- a/src/test/regress/sql/guc.sql
+++ b/src/test/regress/sql/guc.sql
@@ -368,3 +368,13 @@ SELECT name FROM tab_settings_flags
WHERE no_reset AND NOT no_reset_all
ORDER BY 1;
DROP TABLE tab_settings_flags;
+
+-- Test for GUC synchronized standby slots.
+-- Cannot set synchronized_standby_slots to an invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+
+-- Reset the GUC.
+ALTER SYSTEM RESET synchronized_standby_slots;
--
2.34.1
v9_HEAD-0001-Remove-the-validation-from-the-GUC-check-hoo.patchapplication/x-patch; name=v9_HEAD-0001-Remove-the-validation-from-the-GUC-check-hoo.patchDownload
From c951d59cedc78261473c664e5c6b8e479fcaeec4 Mon Sep 17 00:00:00 2001
From: Shlok Kyal <shlok.kyal.oss@gmail.com>
Date: Wed, 10 Sep 2025 15:08:23 +0530
Subject: [PATCH v9_HEAD] Remove the validation from the GUC check hook and add
parsing check
The validation in check_synchronized_standby_slots cannot be run
in postmaster and hence can result inconsistent values in some
backends that inherit the value from postmaster and those
that are started newly. Also, this validation results in parallel
workers fail to with error. This causes all the commands run by
parallel workers to fail, which seems unnecesary. This validation
already happens in StandbySlotsHaveCaughtup() where this GUC is
used, so it can be removed from the GUC check. Also added a
parsing check for the slot names specified in this GUC.
---
src/backend/replication/slot.c | 59 +++++++++----------------------
src/test/regress/expected/guc.out | 15 ++++++++
src/test/regress/sql/guc.sql | 13 +++++++
3 files changed, 44 insertions(+), 43 deletions(-)
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index a4ca363f20d..1e9f4602c69 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -2784,53 +2784,32 @@ GetSlotInvalidationCauseName(ReplicationSlotInvalidationCause cause)
static bool
validate_sync_standby_slots(char *rawname, List **elemlist)
{
- bool ok;
-
/* Verify syntax and parse string into a list of identifiers */
- ok = SplitIdentifierString(rawname, ',', elemlist);
-
- if (!ok)
+ if (!SplitIdentifierString(rawname, ',', elemlist))
{
GUC_check_errdetail("List syntax is invalid.");
+ return false;
}
- else if (MyProc)
+
+ /* Iterate the list to validate each slot name */
+ foreach_ptr(char, name, *elemlist)
{
- /*
- * Check that each specified slot exist and is physical.
- *
- * Because we need an LWLock, we cannot do this on processes without a
- * PGPROC, so we skip it there; but see comments in
- * StandbySlotsHaveCaughtup() as to why that's not a problem.
- */
- LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
+ int err_code;
+ char *err_msg = NULL;
+ char *err_hint = NULL;
- foreach_ptr(char, name, *elemlist)
+ if (!ReplicationSlotValidateNameInternal(name, false, &err_code,
+ &err_msg, &err_hint))
{
- ReplicationSlot *slot;
-
- slot = SearchNamedReplicationSlot(name, false);
-
- if (!slot)
- {
- GUC_check_errdetail("Replication slot \"%s\" does not exist.",
- name);
- ok = false;
- break;
- }
-
- if (!SlotIsPhysical(slot))
- {
- GUC_check_errdetail("\"%s\" is not a physical replication slot.",
- name);
- ok = false;
- break;
- }
+ GUC_check_errcode(err_code);
+ GUC_check_errdetail("%s", err_msg);
+ if (err_hint != NULL)
+ GUC_check_errhint("%s", err_hint);
+ return false;
}
-
- LWLockRelease(ReplicationSlotControlLock);
}
- return ok;
+ return true;
}
/*
@@ -2988,12 +2967,6 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
/*
* If a slot name provided in synchronized_standby_slots does not
* exist, report a message and exit the loop.
- *
- * Though validate_sync_standby_slots (the GUC check_hook) tries to
- * avoid this, it can nonetheless happen because the user can specify
- * a nonexistent slot name before server startup. That function cannot
- * validate such a slot during startup, as ReplicationSlotCtl is not
- * initialized by then. Also, the user might have dropped one slot.
*/
if (!slot)
{
diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out
index 7f9e29c765c..a1bf251b8f3 100644
--- a/src/test/regress/expected/guc.out
+++ b/src/test/regress/expected/guc.out
@@ -913,3 +913,18 @@ SELECT name FROM tab_settings_flags
(0 rows)
DROP TABLE tab_settings_flags;
+-- Test for GUC synchronized standby slots.
+-- Cannot set synchronized_standby_slots to a reserved slot name.
+ALTER SYSTEM SET synchronized_standby_slots='pg_conflict_detection';
+ERROR: invalid value for parameter "synchronized_standby_slots": "pg_conflict_detection"
+DETAIL: replication slot name "pg_conflict_detection" is reserved
+HINT: The name "pg_conflict_detection" is reserved for the conflict detection slot.
+-- Cannot set synchronized_standby_slots to an invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+ERROR: invalid value for parameter "synchronized_standby_slots": "invalid*"
+DETAIL: replication slot name "invalid*" contains invalid character
+HINT: Replication slot names may only contain lower case letters, numbers, and the underscore character.
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+-- Reset the GUC.
+ALTER SYSTEM RESET synchronized_standby_slots;
diff --git a/src/test/regress/sql/guc.sql b/src/test/regress/sql/guc.sql
index f65f84a2632..154bba859a6 100644
--- a/src/test/regress/sql/guc.sql
+++ b/src/test/regress/sql/guc.sql
@@ -368,3 +368,16 @@ SELECT name FROM tab_settings_flags
WHERE no_reset AND NOT no_reset_all
ORDER BY 1;
DROP TABLE tab_settings_flags;
+
+-- Test for GUC synchronized standby slots.
+-- Cannot set synchronized_standby_slots to a reserved slot name.
+ALTER SYSTEM SET synchronized_standby_slots='pg_conflict_detection';
+
+-- Cannot set synchronized_standby_slots to an invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+
+-- Reset the GUC.
+ALTER SYSTEM RESET synchronized_standby_slots;
--
2.34.1
v9_REL_17-0001-Remove-the-validation-from-the-GUC-check-h.txttext/plain; charset=US-ASCII; name=v9_REL_17-0001-Remove-the-validation-from-the-GUC-check-h.txtDownload
From 9aca60e26cb22c13d6876d7868ec0e6fd3c12ff6 Mon Sep 17 00:00:00 2001
From: Shlok Kyal <shlok.kyal.oss@gmail.com>
Date: Thu, 23 Oct 2025 11:09:47 +0530
Subject: [PATCH v9_REL_17] Remove the validation from the GUC check hook and
add parsing check
The validation in check_synchronized_standby_slots cannot be run
in postmaster and hence can result inconsistent values in some
backends that inherit the value from postmaster and those
that are started newly. Also, this validation results in parallel
workers fail to with error. This causes all the commands run by
parallel workers to fail, which seems unnecesary. This validation
already happens in StandbySlotsHaveCaughtup() where this GUC is
used, so it can be removed from the GUC check. Also added a
parsing check for the slot names specified in this GUC.
---
src/backend/replication/slot.c | 59 +++++++++----------------------
src/test/regress/expected/guc.out | 10 ++++++
src/test/regress/sql/guc.sql | 10 ++++++
3 files changed, 36 insertions(+), 43 deletions(-)
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 80b8abde3a2..4bc2be33396 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -2468,53 +2468,32 @@ GetSlotInvalidationCause(const char *invalidation_reason)
static bool
validate_sync_standby_slots(char *rawname, List **elemlist)
{
- bool ok;
-
/* Verify syntax and parse string into a list of identifiers */
- ok = SplitIdentifierString(rawname, ',', elemlist);
-
- if (!ok)
+ if (!SplitIdentifierString(rawname, ',', elemlist))
{
GUC_check_errdetail("List syntax is invalid.");
+ return false;
}
- else if (MyProc)
+
+ /* Iterate the list to validate each slot name */
+ foreach_ptr(char, name, *elemlist)
{
- /*
- * Check that each specified slot exist and is physical.
- *
- * Because we need an LWLock, we cannot do this on processes without a
- * PGPROC, so we skip it there; but see comments in
- * StandbySlotsHaveCaughtup() as to why that's not a problem.
- */
- LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
+ int err_code;
+ char *err_msg = NULL;
+ char *err_hint = NULL;
- foreach_ptr(char, name, *elemlist)
+ if (!ReplicationSlotValidateNameInternal(name, &err_code, &err_msg,
+ &err_hint))
{
- ReplicationSlot *slot;
-
- slot = SearchNamedReplicationSlot(name, false);
-
- if (!slot)
- {
- GUC_check_errdetail("replication slot \"%s\" does not exist",
- name);
- ok = false;
- break;
- }
-
- if (!SlotIsPhysical(slot))
- {
- GUC_check_errdetail("\"%s\" is not a physical replication slot",
- name);
- ok = false;
- break;
- }
+ GUC_check_errcode(err_code);
+ GUC_check_errdetail("%s", err_msg);
+ if (err_hint != NULL)
+ GUC_check_errhint("%s", err_hint);
+ return false;
}
-
- LWLockRelease(ReplicationSlotControlLock);
}
- return ok;
+ return true;
}
/*
@@ -2672,12 +2651,6 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
/*
* If a slot name provided in synchronized_standby_slots does not
* exist, report a message and exit the loop.
- *
- * Though validate_sync_standby_slots (the GUC check_hook) tries to
- * avoid this, it can nonetheless happen because the user can specify
- * a nonexistent slot name before server startup. That function cannot
- * validate such a slot during startup, as ReplicationSlotCtl is not
- * initialized by then. Also, the user might have dropped one slot.
*/
if (!slot)
{
diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out
index 455b6d6c0ce..f03e722a441 100644
--- a/src/test/regress/expected/guc.out
+++ b/src/test/regress/expected/guc.out
@@ -888,3 +888,13 @@ SELECT name FROM tab_settings_flags
(0 rows)
DROP TABLE tab_settings_flags;
+-- Test for GUC synchronized standby slots.
+-- Cannot set synchronized_standby_slots to an invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+ERROR: invalid value for parameter "synchronized_standby_slots": "invalid*"
+DETAIL: replication slot name "invalid*" contains invalid character
+HINT: Replication slot names may only contain lower case letters, numbers, and the underscore character.
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+-- Reset the GUC.
+ALTER SYSTEM RESET synchronized_standby_slots;
diff --git a/src/test/regress/sql/guc.sql b/src/test/regress/sql/guc.sql
index dc79761955d..17ed240bf55 100644
--- a/src/test/regress/sql/guc.sql
+++ b/src/test/regress/sql/guc.sql
@@ -353,3 +353,13 @@ SELECT name FROM tab_settings_flags
WHERE no_reset AND NOT no_reset_all
ORDER BY 1;
DROP TABLE tab_settings_flags;
+
+-- Test for GUC synchronized standby slots.
+-- Cannot set synchronized_standby_slots to an invalid slot name.
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+
+-- Can set synchronized_standby_slots to a non-existent slot name.
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+
+-- Reset the GUC.
+ALTER SYSTEM RESET synchronized_standby_slots;
--
2.34.1
Dear Shlok,
I agree that .pg_reload_conf() is not required. I have removed it in
the latest version of patches.
Thanks for updating the patch!
After considering bit more, I started to feel the test should be under the
test/modules/unsafe_tests. Adding test requires that wal_level >= replica and
max_logical_replication_slots >= 1, but `make installcheck` might allow to run
such an environment. unsafe_tests can ensure that test would be run only while
`make check`. Also, ALTER SYSTEM requires to be superuser and the test has
already used the privileges.
Best regards,
Hayato Kuroda
FUJITSU LIMITED
On Mon, 27 Oct 2025 at 09:35, Hayato Kuroda (Fujitsu)
<kuroda.hayato@fujitsu.com> wrote:
Dear Shlok,
I agree that .pg_reload_conf() is not required. I have removed it in
the latest version of patches.Thanks for updating the patch!
After considering bit more, I started to feel the test should be under the
test/modules/unsafe_tests. Adding test requires that wal_level >= replica and
max_logical_replication_slots >= 1, but `make installcheck` might allow to run
such an environment. unsafe_tests can ensure that test would be run only while
`make check`. Also, ALTER SYSTEM requires to be superuser and the test has
already used the privileges.
Hi Kuroda-san,
I also agree with the analysis. I have added the test in 'guc_privs.sql'.
Thanks,
Shlok Kyal
Attachments:
v10_REL_18-0001-Remove-the-validation-from-the-GUC-check-.txttext/plain; charset=US-ASCII; name=v10_REL_18-0001-Remove-the-validation-from-the-GUC-check-.txtDownload
From cb305a8bd8f96a7b95083d6423c6bc77fe21238e Mon Sep 17 00:00:00 2001
From: Shlok Kyal <shlok.kyal.oss@gmail.com>
Date: Wed, 10 Sep 2025 15:08:23 +0530
Subject: [PATCH v10_REL_18] Remove the validation from the GUC check hook and
add parsing check
The validation in check_synchronized_standby_slots cannot be run
in postmaster and hence can result inconsistent values in some
backends that inherit the value from postmaster and those
that are started newly. Also, this validation results in parallel
workers fail to with error. This causes all the commands run by
parallel workers to fail, which seems unnecesary. This validation
already happens in StandbySlotsHaveCaughtup() where this GUC is
used, so it can be removed from the GUC check. Also added a
parsing check for the slot names specified in this GUC.
---
src/backend/replication/slot.c | 59 +++++--------------
.../unsafe_tests/expected/guc_privs.out | 10 ++++
.../modules/unsafe_tests/sql/guc_privs.sql | 8 +++
3 files changed, 34 insertions(+), 43 deletions(-)
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index ac910f6a74a..101157ed8c9 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -2743,53 +2743,32 @@ GetSlotInvalidationCauseName(ReplicationSlotInvalidationCause cause)
static bool
validate_sync_standby_slots(char *rawname, List **elemlist)
{
- bool ok;
-
/* Verify syntax and parse string into a list of identifiers */
- ok = SplitIdentifierString(rawname, ',', elemlist);
-
- if (!ok)
+ if (!SplitIdentifierString(rawname, ',', elemlist))
{
GUC_check_errdetail("List syntax is invalid.");
+ return false;
}
- else if (MyProc)
+
+ /* Iterate the list to validate each slot name */
+ foreach_ptr(char, name, *elemlist)
{
- /*
- * Check that each specified slot exist and is physical.
- *
- * Because we need an LWLock, we cannot do this on processes without a
- * PGPROC, so we skip it there; but see comments in
- * StandbySlotsHaveCaughtup() as to why that's not a problem.
- */
- LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
+ int err_code;
+ char *err_msg = NULL;
+ char *err_hint = NULL;
- foreach_ptr(char, name, *elemlist)
+ if (!ReplicationSlotValidateNameInternal(name, &err_code, &err_msg,
+ &err_hint))
{
- ReplicationSlot *slot;
-
- slot = SearchNamedReplicationSlot(name, false);
-
- if (!slot)
- {
- GUC_check_errdetail("Replication slot \"%s\" does not exist.",
- name);
- ok = false;
- break;
- }
-
- if (!SlotIsPhysical(slot))
- {
- GUC_check_errdetail("\"%s\" is not a physical replication slot.",
- name);
- ok = false;
- break;
- }
+ GUC_check_errcode(err_code);
+ GUC_check_errdetail("%s", err_msg);
+ if (err_hint != NULL)
+ GUC_check_errhint("%s", err_hint);
+ return false;
}
-
- LWLockRelease(ReplicationSlotControlLock);
}
- return ok;
+ return true;
}
/*
@@ -2947,12 +2926,6 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
/*
* If a slot name provided in synchronized_standby_slots does not
* exist, report a message and exit the loop.
- *
- * Though validate_sync_standby_slots (the GUC check_hook) tries to
- * avoid this, it can nonetheless happen because the user can specify
- * a nonexistent slot name before server startup. That function cannot
- * validate such a slot during startup, as ReplicationSlotCtl is not
- * initialized by then. Also, the user might have dropped one slot.
*/
if (!slot)
{
diff --git a/src/test/modules/unsafe_tests/expected/guc_privs.out b/src/test/modules/unsafe_tests/expected/guc_privs.out
index 6c0ad898341..7f76b675c8c 100644
--- a/src/test/modules/unsafe_tests/expected/guc_privs.out
+++ b/src/test/modules/unsafe_tests/expected/guc_privs.out
@@ -581,6 +581,16 @@ DROP ROLE regress_host_resource_newadmin; -- ok, nothing was transferred
-- Use "drop owned by" so we can drop the role
DROP OWNED BY regress_host_resource_admin; -- ok
DROP ROLE regress_host_resource_admin; -- ok
+-- Test for GUC synchronized standby slots
+-- Cannot set synchronized_standby_slots to an invalid slot name
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+ERROR: invalid value for parameter "synchronized_standby_slots": "invalid*"
+DETAIL: replication slot name "invalid*" contains invalid character
+HINT: Replication slot names may only contain lower case letters, numbers, and the underscore character.
+-- Can set synchronized_standby_slots to a non-existent slot name
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+-- Reset the GUC
+ALTER SYSTEM RESET synchronized_standby_slots;
-- Clean up
RESET SESSION AUTHORIZATION;
DROP ROLE regress_admin; -- ok
diff --git a/src/test/modules/unsafe_tests/sql/guc_privs.sql b/src/test/modules/unsafe_tests/sql/guc_privs.sql
index 9bcbbfa9040..ccbff5a5358 100644
--- a/src/test/modules/unsafe_tests/sql/guc_privs.sql
+++ b/src/test/modules/unsafe_tests/sql/guc_privs.sql
@@ -262,6 +262,14 @@ DROP ROLE regress_host_resource_newadmin; -- ok, nothing was transferred
DROP OWNED BY regress_host_resource_admin; -- ok
DROP ROLE regress_host_resource_admin; -- ok
+-- Test for GUC synchronized standby slots
+-- Cannot set synchronized_standby_slots to an invalid slot name
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+-- Can set synchronized_standby_slots to a non-existent slot name
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+-- Reset the GUC
+ALTER SYSTEM RESET synchronized_standby_slots;
+
-- Clean up
RESET SESSION AUTHORIZATION;
DROP ROLE regress_admin; -- ok
--
2.34.1
v10_HEAD-0001-Remove-the-validation-from-the-GUC-check-ho.patchapplication/octet-stream; name=v10_HEAD-0001-Remove-the-validation-from-the-GUC-check-ho.patchDownload
From c4cc49537864a1043b57ac24038db4e27a0f8d2d Mon Sep 17 00:00:00 2001
From: Shlok Kyal <shlok.kyal.oss@gmail.com>
Date: Wed, 10 Sep 2025 15:08:23 +0530
Subject: [PATCH v10_HEAD] Remove the validation from the GUC check hook and
add parsing check
The validation in check_synchronized_standby_slots cannot be run
in postmaster and hence can result inconsistent values in some
backends that inherit the value from postmaster and those
that are started newly. Also, this validation results in parallel
workers fail to with error. This causes all the commands run by
parallel workers to fail, which seems unnecesary. This validation
already happens in StandbySlotsHaveCaughtup() where this GUC is
used, so it can be removed from the GUC check. Also added a
parsing check for the slot names specified in this GUC.
---
src/backend/replication/slot.c | 59 +++++--------------
.../unsafe_tests/expected/guc_privs.out | 15 +++++
.../modules/unsafe_tests/sql/guc_privs.sql | 10 ++++
3 files changed, 41 insertions(+), 43 deletions(-)
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index a4ca363f20d..1e9f4602c69 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -2784,53 +2784,32 @@ GetSlotInvalidationCauseName(ReplicationSlotInvalidationCause cause)
static bool
validate_sync_standby_slots(char *rawname, List **elemlist)
{
- bool ok;
-
/* Verify syntax and parse string into a list of identifiers */
- ok = SplitIdentifierString(rawname, ',', elemlist);
-
- if (!ok)
+ if (!SplitIdentifierString(rawname, ',', elemlist))
{
GUC_check_errdetail("List syntax is invalid.");
+ return false;
}
- else if (MyProc)
+
+ /* Iterate the list to validate each slot name */
+ foreach_ptr(char, name, *elemlist)
{
- /*
- * Check that each specified slot exist and is physical.
- *
- * Because we need an LWLock, we cannot do this on processes without a
- * PGPROC, so we skip it there; but see comments in
- * StandbySlotsHaveCaughtup() as to why that's not a problem.
- */
- LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
+ int err_code;
+ char *err_msg = NULL;
+ char *err_hint = NULL;
- foreach_ptr(char, name, *elemlist)
+ if (!ReplicationSlotValidateNameInternal(name, false, &err_code,
+ &err_msg, &err_hint))
{
- ReplicationSlot *slot;
-
- slot = SearchNamedReplicationSlot(name, false);
-
- if (!slot)
- {
- GUC_check_errdetail("Replication slot \"%s\" does not exist.",
- name);
- ok = false;
- break;
- }
-
- if (!SlotIsPhysical(slot))
- {
- GUC_check_errdetail("\"%s\" is not a physical replication slot.",
- name);
- ok = false;
- break;
- }
+ GUC_check_errcode(err_code);
+ GUC_check_errdetail("%s", err_msg);
+ if (err_hint != NULL)
+ GUC_check_errhint("%s", err_hint);
+ return false;
}
-
- LWLockRelease(ReplicationSlotControlLock);
}
- return ok;
+ return true;
}
/*
@@ -2988,12 +2967,6 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
/*
* If a slot name provided in synchronized_standby_slots does not
* exist, report a message and exit the loop.
- *
- * Though validate_sync_standby_slots (the GUC check_hook) tries to
- * avoid this, it can nonetheless happen because the user can specify
- * a nonexistent slot name before server startup. That function cannot
- * validate such a slot during startup, as ReplicationSlotCtl is not
- * initialized by then. Also, the user might have dropped one slot.
*/
if (!slot)
{
diff --git a/src/test/modules/unsafe_tests/expected/guc_privs.out b/src/test/modules/unsafe_tests/expected/guc_privs.out
index 6c0ad898341..3cf2f2fdb85 100644
--- a/src/test/modules/unsafe_tests/expected/guc_privs.out
+++ b/src/test/modules/unsafe_tests/expected/guc_privs.out
@@ -581,6 +581,21 @@ DROP ROLE regress_host_resource_newadmin; -- ok, nothing was transferred
-- Use "drop owned by" so we can drop the role
DROP OWNED BY regress_host_resource_admin; -- ok
DROP ROLE regress_host_resource_admin; -- ok
+-- Test for GUC synchronized standby slots
+-- Cannot set synchronized_standby_slots to a reserved slot name
+ALTER SYSTEM SET synchronized_standby_slots='pg_conflict_detection';
+ERROR: invalid value for parameter "synchronized_standby_slots": "pg_conflict_detection"
+DETAIL: replication slot name "pg_conflict_detection" is reserved
+HINT: The name "pg_conflict_detection" is reserved for the conflict detection slot.
+-- Cannot set synchronized_standby_slots to an invalid slot name
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+ERROR: invalid value for parameter "synchronized_standby_slots": "invalid*"
+DETAIL: replication slot name "invalid*" contains invalid character
+HINT: Replication slot names may only contain lower case letters, numbers, and the underscore character.
+-- Can set synchronized_standby_slots to a non-existent slot name
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+-- Reset the GUC
+ALTER SYSTEM RESET synchronized_standby_slots;
-- Clean up
RESET SESSION AUTHORIZATION;
DROP ROLE regress_admin; -- ok
diff --git a/src/test/modules/unsafe_tests/sql/guc_privs.sql b/src/test/modules/unsafe_tests/sql/guc_privs.sql
index 9bcbbfa9040..d0d16f3c29f 100644
--- a/src/test/modules/unsafe_tests/sql/guc_privs.sql
+++ b/src/test/modules/unsafe_tests/sql/guc_privs.sql
@@ -262,6 +262,16 @@ DROP ROLE regress_host_resource_newadmin; -- ok, nothing was transferred
DROP OWNED BY regress_host_resource_admin; -- ok
DROP ROLE regress_host_resource_admin; -- ok
+-- Test for GUC synchronized standby slots
+-- Cannot set synchronized_standby_slots to a reserved slot name
+ALTER SYSTEM SET synchronized_standby_slots='pg_conflict_detection';
+-- Cannot set synchronized_standby_slots to an invalid slot name
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+-- Can set synchronized_standby_slots to a non-existent slot name
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+-- Reset the GUC
+ALTER SYSTEM RESET synchronized_standby_slots;
+
-- Clean up
RESET SESSION AUTHORIZATION;
DROP ROLE regress_admin; -- ok
--
2.34.1
v10_REL_17-0001-Remove-the-validation-from-the-GUC-check-.txttext/plain; charset=US-ASCII; name=v10_REL_17-0001-Remove-the-validation-from-the-GUC-check-.txtDownload
From d4ee208d777fb547006ecd90fe4563803a27e66f Mon Sep 17 00:00:00 2001
From: Shlok Kyal <shlok.kyal.oss@gmail.com>
Date: Thu, 23 Oct 2025 11:09:47 +0530
Subject: [PATCH v10_REL_17] Remove the validation from the GUC check hook and
add parsing check
The validation in check_synchronized_standby_slots cannot be run
in postmaster and hence can result inconsistent values in some
backends that inherit the value from postmaster and those
that are started newly. Also, this validation results in parallel
workers fail to with error. This causes all the commands run by
parallel workers to fail, which seems unnecesary. This validation
already happens in StandbySlotsHaveCaughtup() where this GUC is
used, so it can be removed from the GUC check. Also added a
parsing check for the slot names specified in this GUC.
---
src/backend/replication/slot.c | 59 +++++--------------
.../unsafe_tests/expected/guc_privs.out | 10 ++++
.../modules/unsafe_tests/sql/guc_privs.sql | 8 +++
3 files changed, 34 insertions(+), 43 deletions(-)
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 80b8abde3a2..4bc2be33396 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -2468,53 +2468,32 @@ GetSlotInvalidationCause(const char *invalidation_reason)
static bool
validate_sync_standby_slots(char *rawname, List **elemlist)
{
- bool ok;
-
/* Verify syntax and parse string into a list of identifiers */
- ok = SplitIdentifierString(rawname, ',', elemlist);
-
- if (!ok)
+ if (!SplitIdentifierString(rawname, ',', elemlist))
{
GUC_check_errdetail("List syntax is invalid.");
+ return false;
}
- else if (MyProc)
+
+ /* Iterate the list to validate each slot name */
+ foreach_ptr(char, name, *elemlist)
{
- /*
- * Check that each specified slot exist and is physical.
- *
- * Because we need an LWLock, we cannot do this on processes without a
- * PGPROC, so we skip it there; but see comments in
- * StandbySlotsHaveCaughtup() as to why that's not a problem.
- */
- LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
+ int err_code;
+ char *err_msg = NULL;
+ char *err_hint = NULL;
- foreach_ptr(char, name, *elemlist)
+ if (!ReplicationSlotValidateNameInternal(name, &err_code, &err_msg,
+ &err_hint))
{
- ReplicationSlot *slot;
-
- slot = SearchNamedReplicationSlot(name, false);
-
- if (!slot)
- {
- GUC_check_errdetail("replication slot \"%s\" does not exist",
- name);
- ok = false;
- break;
- }
-
- if (!SlotIsPhysical(slot))
- {
- GUC_check_errdetail("\"%s\" is not a physical replication slot",
- name);
- ok = false;
- break;
- }
+ GUC_check_errcode(err_code);
+ GUC_check_errdetail("%s", err_msg);
+ if (err_hint != NULL)
+ GUC_check_errhint("%s", err_hint);
+ return false;
}
-
- LWLockRelease(ReplicationSlotControlLock);
}
- return ok;
+ return true;
}
/*
@@ -2672,12 +2651,6 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
/*
* If a slot name provided in synchronized_standby_slots does not
* exist, report a message and exit the loop.
- *
- * Though validate_sync_standby_slots (the GUC check_hook) tries to
- * avoid this, it can nonetheless happen because the user can specify
- * a nonexistent slot name before server startup. That function cannot
- * validate such a slot during startup, as ReplicationSlotCtl is not
- * initialized by then. Also, the user might have dropped one slot.
*/
if (!slot)
{
diff --git a/src/test/modules/unsafe_tests/expected/guc_privs.out b/src/test/modules/unsafe_tests/expected/guc_privs.out
index 6c0ad898341..7f76b675c8c 100644
--- a/src/test/modules/unsafe_tests/expected/guc_privs.out
+++ b/src/test/modules/unsafe_tests/expected/guc_privs.out
@@ -581,6 +581,16 @@ DROP ROLE regress_host_resource_newadmin; -- ok, nothing was transferred
-- Use "drop owned by" so we can drop the role
DROP OWNED BY regress_host_resource_admin; -- ok
DROP ROLE regress_host_resource_admin; -- ok
+-- Test for GUC synchronized standby slots
+-- Cannot set synchronized_standby_slots to an invalid slot name
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+ERROR: invalid value for parameter "synchronized_standby_slots": "invalid*"
+DETAIL: replication slot name "invalid*" contains invalid character
+HINT: Replication slot names may only contain lower case letters, numbers, and the underscore character.
+-- Can set synchronized_standby_slots to a non-existent slot name
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+-- Reset the GUC
+ALTER SYSTEM RESET synchronized_standby_slots;
-- Clean up
RESET SESSION AUTHORIZATION;
DROP ROLE regress_admin; -- ok
diff --git a/src/test/modules/unsafe_tests/sql/guc_privs.sql b/src/test/modules/unsafe_tests/sql/guc_privs.sql
index 9bcbbfa9040..ccbff5a5358 100644
--- a/src/test/modules/unsafe_tests/sql/guc_privs.sql
+++ b/src/test/modules/unsafe_tests/sql/guc_privs.sql
@@ -262,6 +262,14 @@ DROP ROLE regress_host_resource_newadmin; -- ok, nothing was transferred
DROP OWNED BY regress_host_resource_admin; -- ok
DROP ROLE regress_host_resource_admin; -- ok
+-- Test for GUC synchronized standby slots
+-- Cannot set synchronized_standby_slots to an invalid slot name
+ALTER SYSTEM SET synchronized_standby_slots='invalid*';
+-- Can set synchronized_standby_slots to a non-existent slot name
+ALTER SYSTEM SET synchronized_standby_slots='missing';
+-- Reset the GUC
+ALTER SYSTEM RESET synchronized_standby_slots;
+
-- Clean up
RESET SESSION AUTHORIZATION;
DROP ROLE regress_admin; -- ok
--
2.34.1