From 30250e100b8be4beaf5566a3b58da4edc161f097 Mon Sep 17 00:00:00 2001
From: debebantur <stepan.filippov@yandex.ru>
Date: Mon, 7 Sep 2026 08:37:02 +0000
Subject: [PATCH] changed end of recovery timeline

---
 src/backend/access/transam/xlog.c         |  2 +-
 src/test/recovery/t/002_archiving.pl      | 18 ++++++++++++++++++
 src/test/recovery/t/028_pitr_timelines.pl |  9 +++++++++
 3 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index f85b528608..6b0b27d853 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -6408,7 +6408,7 @@ StartupXLOG(void)
 		 * To minimize the window for that, try to do as little as possible
 		 * between here and writing the end-of-recovery record.
 		 */
-		writeTimeLineHistory(newTLI, recoveryTargetTLI,
+		writeTimeLineHistory(newTLI, endOfRecoveryInfo->lastRecTLI,
 							 EndOfLog, endOfRecoveryInfo->recoveryStopReason);
 
 		ereport(LOG,
diff --git a/src/test/recovery/t/002_archiving.pl b/src/test/recovery/t/002_archiving.pl
index aa40f58e6d..b66aaefbfd 100644
--- a/src/test/recovery/t/002_archiving.pl
+++ b/src/test/recovery/t/002_archiving.pl
@@ -100,6 +100,20 @@ $caughtup_query =
 $node_primary->poll_query_until('postgres', $caughtup_query)
   or die "Timed out while waiting for archiving of 00000002.history";
 
+# Generate and archive some WAL on timeline 2.  This ensures that standby2
+# actually reaches timeline 2, so that its history file is needed again when
+# standby2 is promoted.
+$node_standby->safe_psql('postgres', "CREATE TABLE timeline_2_marker (a int)");
+my $timeline_2_lsn =
+  $node_standby->safe_psql('postgres', "SELECT pg_current_wal_lsn()");
+my $timeline_2_walfile = $node_standby->safe_psql(
+	'postgres', "SELECT pg_walfile_name('$timeline_2_lsn')");
+$node_standby->safe_psql('postgres', "SELECT pg_switch_wal()");
+$caughtup_query =
+  "SELECT size IS NOT NULL FROM pg_stat_file('$primary_archive/$timeline_2_walfile', true)";
+$node_primary->poll_query_until('postgres', $caughtup_query)
+  or die "Timed out while waiting for archiving of $timeline_2_walfile";
+
 # recovery_end_command should have been triggered on promotion.
 ok( -f "$data_dir/$recovery_end_command_file",
 	'recovery_end_command executed after promotion');
@@ -131,6 +145,10 @@ $node_standby2->start;
 # Save the log location, to see the failure of recovery_end_command.
 my $log_location = -s $node_standby2->logfile;
 
+$caughtup_query = "SELECT '$timeline_2_lsn'::pg_lsn <= pg_last_wal_replay_lsn()";
+$node_standby2->poll_query_until('postgres', $caughtup_query)
+    or die "Timed out while waiting for standby2 to reach timeline 2";
+
 # Now promote standby2, and check that temporary files specifically
 # generated during archive recovery are removed by the end of recovery.
 $node_standby2->promote;
diff --git a/src/test/recovery/t/028_pitr_timelines.pl b/src/test/recovery/t/028_pitr_timelines.pl
index ae617f6195..429b6e8220 100644
--- a/src/test/recovery/t/028_pitr_timelines.pl
+++ b/src/test/recovery/t/028_pitr_timelines.pl
@@ -150,6 +150,15 @@ $node_pitr->poll_query_until('postgres',
 # Stop the node.  This archives the last segment.
 $node_pitr->stop();
 
+# The new timeline branched from timeline 1 at the recovery target, before
+# timeline 2 branched from timeline 1.  Its history must therefore name
+# timeline 1 as its direct parent, rather than copying timeline 2's history.
+my $history = slurp_file($node_primary->archive_dir . '/00000003.history');
+like(
+	$history,
+	qr/^1\t[0-9A-F]+\/[0-9A-F]+\t[^\r\n]*(?:\r?\n)?\z/,
+	"new timeline history has the timeline containing the target as parent");
+
 # Test archive recovery on the timeline created by the PITR.  This
 # replays the end-of-recovery record that switches from timeline 1 to
 # 3.
-- 
2.34.1

