From efd766f3e5233aae1d1dac3f057d231054a1cf08 Mon Sep 17 00:00:00 2001
From: Andrey Borodin <amborodin@acm.org>
Date: Wed, 22 Jul 2026 15:32:35 +0500
Subject: [PATCH v7-AB-edited 5/6] fixup! Add archive_mode=shared for
 coordinated WAL archiving

Fix Windows portability of the shared-archive TAP tests.

055 configured archive_command as a Unix cp invocation with the raw
tempdir path interpolated into postgresql.conf.  On Windows the path
contains backslashes, and the GUC parser processes backslash escapes
inside quoted configuration values, so the path got mangled (\t became
a tab, \b a backspace, ...) and archiving never succeeded; the test
then died waiting for archived_count > 0 (389 s timeout in CI).

Construct the archive command the way
PostgreSQL::Test::Cluster::enable_archiving does: use copy on Windows
and double the backslashes.  We cannot use enable_archiving itself
because all nodes must share a single archive directory, which is the
point of archive_mode=shared.

056 already used copy on Windows but did not double the backslashes in
the destination path; apply the same treatment there.  The doubled
form also survives the ALTER SYSTEM round-trip: write_auto_conf_file()
escapes only single quotes, and DeescapeQuotedString() collapses the
doubled backslashes on re-read, same as for postgresql.conf.
---
 src/test/recovery/t/055_archive_shared.pl     | 22 +++++++++++++++----
 .../t/056_archive_shared_checkpoint.pl        |  9 ++++++--
 2 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/src/test/recovery/t/055_archive_shared.pl b/src/test/recovery/t/055_archive_shared.pl
index f86594893c0..00e12ef95f1 100644
--- a/src/test/recovery/t/055_archive_shared.pl
+++ b/src/test/recovery/t/055_archive_shared.pl
@@ -8,14 +8,28 @@ use PostgreSQL::Test::Utils;
 use Test::More;
 use File::Path qw(rmtree);
 
-# Initialize primary node with archiving
+# Initialize primary node with archiving.
+#
+# All nodes share one archive directory (that is the point of
+# archive_mode=shared), so we cannot rely on enable_archiving's per-node
+# archive dir and construct the command ourselves.  Mirror the portability
+# dance of PostgreSQL::Test::Cluster::enable_archiving: on Windows use copy,
+# and double the backslashes because the GUC parser processes backslash
+# escapes in quoted configuration values.
 my $archive_dir = PostgreSQL::Test::Utils::tempdir();
+my $archive_path = $archive_dir;
+$archive_path =~ s{\\}{\\\\}g if $PostgreSQL::Test::Utils::windows_os;
+my $archive_command =
+  $PostgreSQL::Test::Utils::windows_os
+  ? qq{copy "%p" "$archive_path\\\\%f"}
+  : qq{cp %p "$archive_path/%f"};
+
 my $primary = PostgreSQL::Test::Cluster->new('primary');
 $primary->init(has_archiving => 1, allows_streaming => 1);
 $primary->append_conf('postgresql.conf', "
 archive_mode = shared
 archive_status_report_interval = 10ms
-archive_command = 'cp %p \"$archive_dir\"/%f'
+archive_command = '$archive_command'
 wal_keep_size = 128MB
 ");
 $primary->start;
@@ -52,7 +66,7 @@ $standby->init_from_backup($primary, $backup_name, has_streaming => 1);
 $standby->append_conf('postgresql.conf', "
 archive_mode = shared
 archive_status_report_interval = 10ms
-archive_command = 'cp %p \"$archive_dir\"/%f'
+archive_command = '$archive_command'
 wal_receiver_status_interval = 1s
 ");
 $standby->start;
@@ -137,7 +151,7 @@ $cascade_standby->init_from_backup($standby, $promoted_backup, has_streaming =>
 $cascade_standby->append_conf('postgresql.conf', "
 archive_mode = shared
 archive_status_report_interval = 10ms
-archive_command = 'cp %p \"$archive_dir\"/%f'
+archive_command = '$archive_command'
 wal_receiver_status_interval = 1s
 ");
 $cascade_standby->start;
diff --git a/src/test/recovery/t/056_archive_shared_checkpoint.pl b/src/test/recovery/t/056_archive_shared_checkpoint.pl
index 8083ee99513..70d59454dd5 100644
--- a/src/test/recovery/t/056_archive_shared_checkpoint.pl
+++ b/src/test/recovery/t/056_archive_shared_checkpoint.pl
@@ -28,11 +28,16 @@ my $broken_command =
   ? q{copy "%p_does_not_exist" "%f_does_not_exist"}
   : q{cp "%p_does_not_exist" "%f_does_not_exist"};
 
+# Double the backslashes on Windows: the GUC parser processes backslash
+# escapes in quoted configuration values (see also
+# PostgreSQL::Test::Cluster::enable_archiving).
 my $archive_dir = PostgreSQL::Test::Utils::tempdir();
+my $archive_path = $archive_dir;
+$archive_path =~ s{\\}{\\\\}g if $PostgreSQL::Test::Utils::windows_os;
 my $good_command =
   $PostgreSQL::Test::Utils::windows_os
-  ? qq{copy "%p" "$archive_dir\\%f"}
-  : qq{cp %p "$archive_dir/%f"};
+  ? qq{copy "%p" "$archive_path\\\\%f"}
+  : qq{cp %p "$archive_path/%f"};
 
 ###############################################################################
 # Set up primary with archive_mode=shared and BROKEN archiving so that every
-- 
2.50.1 (Apple Git-155)

