agora inbox for pgsql-hackers@postgresql.orghelp / color / mirror / Atom feed
[PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race 732+ messages / 1 participants [nested] [flat]
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --HitlKQoyB8givWgr-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-08 07:05 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-08 07:05 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../t/035_standby_logical_decoding.pl | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index ce80123844d..146c33ce39d 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1082,6 +1084,9 @@ $node_standby->wait_for_replay_catchup($node_cascading_standby); $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1112,6 +1117,14 @@ my $handle2 = IPC::Run::start( '2>' => \$stderr2, IPC::Run::timeout($default_timeout)); +# Issue SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +$decode_session->query_until( + qr/decoding_started/, qq( + \\echo decoding_started + SELECT count(*) FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +)); + # Wait for the walsender to acquire the slot. $node_cascading_standby->poll_query_until('testdb', qq[SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'race_slot' AND active_pid IS NOT NULL)] @@ -1121,9 +1134,18 @@ $node_cascading_standby->poll_query_until('testdb', $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -# Verify pg_recvlogical successfully decodes the data. +# Verify pg_recvlogical successfully decodes the data (walsender path). $pump_timeout = IPC::Run::timer($default_timeout); ok( pump_until($handle2, $pump_timeout, \$stdout2, qr/COMMIT/s), 'pg_recvlogical works during promotion timeline switch'); +# Verify SQL decoding returns a numeric result (read_local_xlog_page_guts path). +my $sql_timeout = IPC::Run::timer($default_timeout); +ok( pump_until( + $decode_session->{run}, $sql_timeout, + \$decode_session->{stdout}, qr/\d+/m), + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + +$decode_session->quit; + done_testing(); -- 2.34.1 --KccnfG1O+OuiQe+b-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
* [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race @ 2026-06-09 09:56 Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 0 siblings, 0 replies; 732+ messages in thread From: Bertrand Drouvot @ 2026-06-09 09:56 UTC (permalink / raw) Extend the injection-point test in 035_standby_logical_decoding.pl to also cover the SQL-callable decoding path (pg_logical_slot_peek_changes) which exercises read_local_xlog_page_guts(). The test uses the same promotion and injection point as the walsender test: a background psql session is connected before promotion, then issues pg_logical_slot_peek_changes while startup is paused at the injection point. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com --- .../recovery/t/035_standby_logical_decoding.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 100.0% src/test/recovery/t/ diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl index 9b45c819241..6ec338ebf32 100644 --- a/src/test/recovery/t/035_standby_logical_decoding.pl +++ b/src/test/recovery/t/035_standby_logical_decoding.pl @@ -1068,11 +1068,13 @@ is($cascading_stdout, $expected, # timeline in this window. ################################################## -# Create a logical slot on the cascading standby for this test. +# Create logical slots on the cascading standby for this test. $node_cascading_standby->create_logical_slot_on_standby($node_standby, 'race_slot', 'testdb'); +$node_cascading_standby->create_logical_slot_on_standby($node_standby, + 'race_slot_sql', 'testdb'); -# Insert data so the slot has WAL to decode. +# Insert data so the slots have WAL to decode. $node_standby->safe_psql('testdb', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(10,13) s;] ); @@ -1089,6 +1091,9 @@ COMMIT}; $node_standby->safe_psql('testdb', 'CREATE EXTENSION injection_points;'); $node_standby->wait_for_replay_catchup($node_cascading_standby); +# Open a background psql session BEFORE promotion for the SQL decoding test. +my $decode_session = $node_cascading_standby->background_psql('testdb'); + # Attach injection point to pause startup after WAL segment cleanup # but before RecoveryInProgress() flips to false. $node_cascading_standby->safe_psql('testdb', @@ -1130,6 +1135,14 @@ is($stdout2, $expected, 'got expected output from pg_recvlogical during promotion timeline switch' ); +# Verify SQL decoding (read_local_xlog_page_guts path) on the pre-connected +# session. +my $sql_out = $decode_session->query_safe( + "SELECT data FROM pg_logical_slot_peek_changes('race_slot_sql', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')" +); +is($sql_out, $expected, + 'pg_logical_slot_peek_changes works during promotion timeline switch'); + # Resume promotion. $node_cascading_standby->safe_psql('testdb', "SELECT injection_points_wakeup('promotion-after-wal-segment-cleanup');"); -- 2.34.1 --Wctt8FE9hhxDGrBZ-- ^ permalink raw reply [nested|flat] 732+ messages in thread
end of thread, other threads:[~2026-06-09 09:56 UTC | newest] Thread overview: 732+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-08 07:05 [PATCH v1 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com> 2026-06-09 09:56 [PATCH v2 4/4] Add SQL-path test for read_local_xlog_page_guts() timeline race Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox