@@ -276,7 +276,8 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt,
276276 * because it's needed to form the name of xlog file.
277277 */
278278 validate_wal (dest_backup , arclog_path , rt -> recovery_target_time ,
279- rt -> recovery_target_xid , base_full_backup -> tli );
279+ rt -> recovery_target_xid , rt -> recovery_target_lsn ,
280+ base_full_backup -> tli );
280281
281282 /* Set every incremental backup between corrupted backup and nearest FULL backup as orphans */
282283 if (corrupted_backup )
@@ -335,6 +336,11 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt,
335336 for (i = base_full_backup_index ; i >= dest_backup_index ; i -- )
336337 {
337338 pgBackup * backup = (pgBackup * ) parray_get (backups , i );
339+
340+ if (rt -> lsn_specified && parse_server_version (backup -> server_version ) < 100000 )
341+ elog (ERROR , "Backup %s was created for version %s which doesn't support recovery_target_lsn" ,
342+ base36enc (dest_backup -> start_time ), dest_backup -> server_version );
343+
338344 restore_backup (backup );
339345 }
340346
@@ -837,6 +843,9 @@ create_recovery_conf(time_t backup_id,
837843 if (rt -> xid_specified )
838844 fprintf (fp , "recovery_target_xid = '%s'\n" , rt -> target_xid_string );
839845
846+ if (rt -> recovery_target_lsn )
847+ fprintf (fp , "recovery_target_lsn = '%s'\n" , rt -> target_lsn_string );
848+
840849 if (rt -> recovery_target_immediate )
841850 fprintf (fp , "recovery_target = 'immediate'\n" );
842851
@@ -981,6 +990,9 @@ satisfy_recovery_target(const pgBackup *backup, const pgRecoveryTarget *rt)
981990 if (rt -> time_specified )
982991 return backup -> recovery_time <= rt -> recovery_target_time ;
983992
993+ if (rt -> lsn_specified )
994+ return backup -> stop_lsn <= rt -> recovery_target_lsn ;
995+
984996 return true;
985997}
986998
@@ -1009,6 +1021,7 @@ parseRecoveryTargetOptions(const char *target_time,
10091021 const char * target_xid ,
10101022 const char * target_inclusive ,
10111023 TimeLineID target_tli ,
1024+ const char * target_lsn ,
10121025 bool target_immediate ,
10131026 const char * target_name ,
10141027 const char * target_action ,
@@ -1017,6 +1030,7 @@ parseRecoveryTargetOptions(const char *target_time,
10171030 time_t dummy_time ;
10181031 TransactionId dummy_xid ;
10191032 bool dummy_bool ;
1033+ XLogRecPtr dummy_lsn ;
10201034 /*
10211035 * count the number of the mutually exclusive options which may specify
10221036 * recovery target. If final value > 1, throw an error.
@@ -1028,10 +1042,13 @@ parseRecoveryTargetOptions(const char *target_time,
10281042 rt -> time_specified = false;
10291043 rt -> xid_specified = false;
10301044 rt -> inclusive_specified = false;
1045+ rt -> lsn_specified = false;
10311046 rt -> recovery_target_time = 0 ;
10321047 rt -> recovery_target_xid = 0 ;
1048+ rt -> recovery_target_lsn = InvalidXLogRecPtr ;
10331049 rt -> target_time_string = NULL ;
10341050 rt -> target_xid_string = NULL ;
1051+ rt -> target_lsn_string = NULL ;
10351052 rt -> recovery_target_inclusive = false;
10361053 rt -> recovery_target_tli = 0 ;
10371054 rt -> recovery_target_immediate = false;
@@ -1068,6 +1085,17 @@ parseRecoveryTargetOptions(const char *target_time,
10681085 elog (ERROR , "Invalid value of --xid option %s" , target_xid );
10691086 }
10701087
1088+ if (target_lsn )
1089+ {
1090+ recovery_target_specified ++ ;
1091+ rt -> lsn_specified = true;
1092+ rt -> target_lsn_string = target_lsn ;
1093+ if (parse_lsn (target_lsn , & dummy_lsn ))
1094+ rt -> recovery_target_lsn = dummy_lsn ;
1095+ else
1096+ elog (ERROR , "Invalid value of --lsn option %s" , target_lsn );
1097+ }
1098+
10711099 if (target_inclusive )
10721100 {
10731101 rt -> inclusive_specified = true;
@@ -1112,10 +1140,10 @@ parseRecoveryTargetOptions(const char *target_time,
11121140
11131141 /* More than one mutually exclusive option was defined. */
11141142 if (recovery_target_specified > 1 )
1115- elog (ERROR , "At most one of --immediate, --target-name, --time, or --xid can be used" );
1143+ elog (ERROR , "At most one of --immediate, --target-name, --time, --xid, or --lsn can be used" );
11161144
11171145 /* If none of the options is defined, '--inclusive' option is meaningless */
1118- if (!(rt -> xid_specified || rt -> time_specified ) && rt -> recovery_target_inclusive )
1146+ if (!(rt -> xid_specified || rt -> time_specified || rt -> lsn_specified ) && rt -> recovery_target_inclusive )
11191147 elog (ERROR , "--inclusive option applies when either --time or --xid is specified" );
11201148
11211149 return rt ;
0 commit comments