@@ -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
@@ -838,6 +844,9 @@ create_recovery_conf(time_t backup_id,
838844 if (rt -> xid_specified )
839845 fprintf (fp , "recovery_target_xid = '%s'\n" , rt -> target_xid_string );
840846
847+ if (rt -> recovery_target_lsn )
848+ fprintf (fp , "recovery_target_lsn = '%s'\n" , rt -> target_lsn_string );
849+
841850 if (rt -> recovery_target_immediate )
842851 fprintf (fp , "recovery_target = 'immediate'\n" );
843852
@@ -982,6 +991,9 @@ satisfy_recovery_target(const pgBackup *backup, const pgRecoveryTarget *rt)
982991 if (rt -> time_specified )
983992 return backup -> recovery_time <= rt -> recovery_target_time ;
984993
994+ if (rt -> lsn_specified )
995+ return backup -> stop_lsn <= rt -> recovery_target_lsn ;
996+
985997 return true;
986998}
987999
@@ -1010,6 +1022,7 @@ parseRecoveryTargetOptions(const char *target_time,
10101022 const char * target_xid ,
10111023 const char * target_inclusive ,
10121024 TimeLineID target_tli ,
1025+ const char * target_lsn ,
10131026 bool target_immediate ,
10141027 const char * target_name ,
10151028 const char * target_action ,
@@ -1018,6 +1031,7 @@ parseRecoveryTargetOptions(const char *target_time,
10181031 time_t dummy_time ;
10191032 TransactionId dummy_xid ;
10201033 bool dummy_bool ;
1034+ XLogRecPtr dummy_lsn ;
10211035 /*
10221036 * count the number of the mutually exclusive options which may specify
10231037 * recovery target. If final value > 1, throw an error.
@@ -1029,10 +1043,13 @@ parseRecoveryTargetOptions(const char *target_time,
10291043 rt -> time_specified = false;
10301044 rt -> xid_specified = false;
10311045 rt -> inclusive_specified = false;
1046+ rt -> lsn_specified = false;
10321047 rt -> recovery_target_time = 0 ;
10331048 rt -> recovery_target_xid = 0 ;
1049+ rt -> recovery_target_lsn = InvalidXLogRecPtr ;
10341050 rt -> target_time_string = NULL ;
10351051 rt -> target_xid_string = NULL ;
1052+ rt -> target_lsn_string = NULL ;
10361053 rt -> recovery_target_inclusive = false;
10371054 rt -> recovery_target_tli = 0 ;
10381055 rt -> recovery_target_immediate = false;
@@ -1069,6 +1086,17 @@ parseRecoveryTargetOptions(const char *target_time,
10691086 elog (ERROR , "Invalid value of --xid option %s" , target_xid );
10701087 }
10711088
1089+ if (target_lsn )
1090+ {
1091+ recovery_target_specified ++ ;
1092+ rt -> lsn_specified = true;
1093+ rt -> target_lsn_string = target_lsn ;
1094+ if (parse_lsn (target_lsn , & dummy_lsn ))
1095+ rt -> recovery_target_lsn = dummy_lsn ;
1096+ else
1097+ elog (ERROR , "Invalid value of --lsn option %s" , target_lsn );
1098+ }
1099+
10721100 if (target_inclusive )
10731101 {
10741102 rt -> inclusive_specified = true;
@@ -1113,10 +1141,10 @@ parseRecoveryTargetOptions(const char *target_time,
11131141
11141142 /* More than one mutually exclusive option was defined. */
11151143 if (recovery_target_specified > 1 )
1116- elog (ERROR , "At most one of --immediate, --target-name, --time, or --xid can be used" );
1144+ elog (ERROR , "At most one of --immediate, --target-name, --time, --xid, or --lsn can be used" );
11171145
11181146 /* If none of the options is defined, '--inclusive' option is meaningless */
1119- if (!(rt -> xid_specified || rt -> time_specified ) && rt -> recovery_target_inclusive )
1147+ if (!(rt -> xid_specified || rt -> time_specified || rt -> lsn_specified ) && rt -> recovery_target_inclusive )
11201148 elog (ERROR , "--inclusive option applies when either --time or --xid is specified" );
11211149
11221150 return rt ;
0 commit comments