diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index de77f14573..462f27fc04 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -3858,7 +3858,8 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"' # Windows
This parameter specifies the time stamp up to which recovery
will proceed.
The precise stopping point is also influenced by
- .
+ and
+ .
@@ -3939,6 +3940,27 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"' # Windows
+
+ recovery_target_use_origin_time (boolean)
+
+ recovery_target_use_origin_time configuration parameter
+
+
+
+
+ Specifies whether to use the timestamp from the local commit
+ record (off), or, if one exists, to use
+ the timestamp as recorded by the origin, for commits that
+ arrive by logical replication from another server.
+ This allows a PITR recovery to have a single consistent
+ timestamp across multiple servers, if that is desirable.
+ Applies when
+ is specified. Default is on.
+
+
+
+
recovery_target_timeline (string)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 0a0771a18e..9c0c5e389c 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -275,6 +275,7 @@ char *recoveryEndCommand = NULL;
char *archiveCleanupCommand = NULL;
RecoveryTargetType recoveryTarget = RECOVERY_TARGET_UNSET;
bool recoveryTargetInclusive = true;
+bool recoveryTargetUseOriginTime = false;
int recoveryTargetAction = RECOVERY_TARGET_ACTION_PAUSE;
TransactionId recoveryTargetXid;
char *recovery_target_time_string;
@@ -5840,25 +5841,81 @@ static bool
getRecordTimestamp(XLogReaderState *record, TimestampTz *recordXtime)
{
uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
- uint8 xact_info = info & XLOG_XACT_OPMASK;
uint8 rmid = XLogRecGetRmid(record);
- if (rmid == RM_XLOG_ID && info == XLOG_RESTORE_POINT)
+ if (rmid == RM_XLOG_ID)
{
- *recordXtime = ((xl_restore_point *) XLogRecGetData(record))->rp_time;
- return true;
- }
- if (rmid == RM_XACT_ID && (xact_info == XLOG_XACT_COMMIT ||
- xact_info == XLOG_XACT_COMMIT_PREPARED))
- {
- *recordXtime = ((xl_xact_commit *) XLogRecGetData(record))->xact_time;
- return true;
+ if (info == XLOG_RESTORE_POINT)
+ {
+ *recordXtime = ((xl_restore_point *) XLogRecGetData(record))->rp_time;
+ return true;
+ }
+ if (info == XLOG_CHECKPOINT_ONLINE ||
+ info == XLOG_CHECKPOINT_SHUTDOWN)
+ {
+ *recordXtime = time_t_to_timestamptz(((CheckPoint *) XLogRecGetData(record))->time);
+ return true;
+ }
+ if (info == XLOG_END_OF_RECOVERY)
+ {
+ *recordXtime = ((xl_end_of_recovery *) XLogRecGetData(record))->end_time;
+ return true;
+ }
}
- if (rmid == RM_XACT_ID && (xact_info == XLOG_XACT_ABORT ||
- xact_info == XLOG_XACT_ABORT_PREPARED))
+ if (rmid == RM_XACT_ID)
{
- *recordXtime = ((xl_xact_abort *) XLogRecGetData(record))->xact_time;
- return true;
+ uint8 xact_info = info & XLOG_XACT_OPMASK;
+
+ if (xact_info == XLOG_XACT_COMMIT ||
+ xact_info == XLOG_XACT_COMMIT_PREPARED)
+ {
+ if (recoveryTargetUseOriginTime)
+ {
+ xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record);
+ xl_xact_parsed_commit parsed;
+
+ ParseCommitRecord(XLogRecGetInfo(record),
+ xlrec,
+ &parsed);
+ *recordXtime = parsed.origin_timestamp;
+ }
+ else
+ *recordXtime = ((xl_xact_commit *) XLogRecGetData(record))->xact_time;
+ return true;
+ }
+ if (xact_info == XLOG_XACT_ABORT ||
+ xact_info == XLOG_XACT_ABORT_PREPARED)
+ {
+ if (recoveryTargetUseOriginTime)
+ {
+ xl_xact_abort *xlrec = (xl_xact_abort *) XLogRecGetData(record);
+ xl_xact_parsed_abort parsed;
+
+ ParseAbortRecord(XLogRecGetInfo(record),
+ xlrec,
+ &parsed);
+ *recordXtime = parsed.origin_timestamp;
+ }
+ else
+ *recordXtime = ((xl_xact_abort *) XLogRecGetData(record))->xact_time;
+ return true;
+ }
+ if (xact_info == XLOG_XACT_PREPARE)
+ {
+ if (recoveryTargetUseOriginTime)
+ {
+ xl_xact_prepare *xlrec = (xl_xact_prepare *) XLogRecGetData(record);
+ xl_xact_parsed_prepare parsed;
+
+ ParsePrepareRecord(XLogRecGetInfo(record),
+ xlrec,
+ &parsed);
+ *recordXtime = parsed.origin_timestamp;
+ }
+ else
+ *recordXtime = ((xl_xact_prepare *) XLogRecGetData(record))->prepared_at;
+ return true;
+ }
}
return false;
}
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index e91d5a3cfd..9693afc602 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -1906,6 +1906,16 @@ static struct config_bool ConfigureNamesBool[] =
NULL, NULL, NULL
},
+ {
+ {"recovery_target_use_origin_time", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
+ gettext_noop("Sets whether to use local or origin transaction time with recovery target."),
+ NULL
+ },
+ &recoveryTargetUseOriginTime,
+ false,
+ NULL, NULL, NULL
+ },
+
{
{"hot_standby", PGC_POSTMASTER, REPLICATION_STANDBY,
gettext_noop("Allows connections and queries during recovery."),
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index c0a560204b..65c6633c0d 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -84,6 +84,7 @@ extern char *recoveryRestoreCommand;
extern char *recoveryEndCommand;
extern char *archiveCleanupCommand;
extern bool recoveryTargetInclusive;
+extern bool recoveryTargetUseOriginTime;
extern int recoveryTargetAction;
extern int recovery_min_apply_delay;
extern char *PrimaryConnInfo;