*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
***************
*** 79,84 **** bool		fullPageWrites = true;
--- 79,98 ----
  bool		log_checkpoints = false;
  int			sync_method = DEFAULT_SYNC_METHOD;
  int			wal_level = WAL_LEVEL_MINIMAL;
+ char	   *restore_command = NULL;
+ char	   *archive_cleanup_command = NULL;
+ char	   *recovery_end_command = NULL;
+ bool		standby_mode = false;
+ char	   *primary_conninfo = NULL;
+ char	   *trigger_file = NULL;
+ RecoveryTargetType	recovery_target = RECOVERY_TARGET_UNSET;
+ TransactionId	recovery_target_xid = InvalidTransactionId;
+ TimestampTz	recovery_target_time = 0;
+ char	   *recovery_target_name = NULL;
+ bool		recovery_target_inclusive = true;
+ bool		pause_at_recovery_target = true;
+ char	   *recovery_target_timeline_string = NULL;
+ TimeLineID	recovery_target_timeline = 0;
  
  #ifdef WAL_DEBUG
  bool		XLOG_DEBUG = false;
***************
*** 185,207 **** static bool InArchiveRecovery = false;
  /* Was the last xlog file restored from archive, or local? */
  static bool restoredFromArchive = false;
  
! /* options taken from recovery.conf for archive recovery */
! static char *recoveryRestoreCommand = NULL;
! static char *recoveryEndCommand = NULL;
! static char *archiveCleanupCommand = NULL;
! static RecoveryTargetType recoveryTarget = RECOVERY_TARGET_UNSET;
! static bool recoveryTargetInclusive = true;
! static bool recoveryPauseAtTarget = true;
! static TransactionId recoveryTargetXid;
! static TimestampTz recoveryTargetTime;
! static char *recoveryTargetName;
! 
! /* options taken from recovery.conf for XLOG streaming */
! static bool StandbyMode = false;
! static char *PrimaryConnInfo = NULL;
! static char *TriggerFile = NULL;
! 
! /* if recoveryStopsHere returns true, it saves actual stop xid/time/name here */
  static TransactionId recoveryStopXid;
  static TimestampTz recoveryStopTime;
  static char recoveryStopName[MAXFNAMELEN];
--- 199,206 ----
  /* Was the last xlog file restored from archive, or local? */
  static bool restoredFromArchive = false;
  
! /* if recoveryStopsHere returns true, it saves actual stop type/xid/time/name here */
! static RecoveryTargetType recoveryStopTarget;
  static TransactionId recoveryStopXid;
  static TimestampTz recoveryStopTime;
  static char recoveryStopName[MAXFNAMELEN];
***************
*** 407,416 **** typedef struct XLogCtlData
  	TimeLineID	RecoveryTargetTLI;
  
  	/*
! 	 * archiveCleanupCommand is read from recovery.conf but needs to be in
! 	 * shared memory so that the bgwriter process can access it.
  	 */
! 	char		archiveCleanupCommand[MAXPGPATH];
  
  	/*
  	 * SharedRecoveryInProgress indicates if we're still in crash or archive
--- 406,415 ----
  	TimeLineID	RecoveryTargetTLI;
  
  	/*
! 	 * archive_cleanup_command can be read from recovery.conf but needs
! 	 * to be in shared memory so that the bgwriter process can access it.
  	 */
! 	char		archive_cleanup_command[MAXPGPATH];
  
  	/*
  	 * SharedRecoveryInProgress indicates if we're still in crash or archive
***************
*** 611,616 **** static void SetRecoveryPause(bool recoveryPause);
--- 610,616 ----
  static void SetLatestXTime(TimestampTz xtime);
  static TimestampTz GetLatestXTime(void);
  static void CheckRequiredParameterValues(void);
+ static void CheckRestoreCommandSet(void);
  static void XLogReportParameters(void);
  static void LocalSetXLogInsertAllowed(void);
  static void CheckPointGuts(XLogRecPtr checkPointRedo, int flags);
***************
*** 2931,2937 **** RestoreArchivedFile(char *path, const char *xlogfname,
  	uint32		restartSeg;
  
  	/* In standby mode, restore_command might not be supplied */
! 	if (recoveryRestoreCommand == NULL)
  		goto not_available;
  
  	/*
--- 2931,2937 ----
  	uint32		restartSeg;
  
  	/* In standby mode, restore_command might not be supplied */
! 	if (!restore_command[0])
  		goto not_available;
  
  	/*
***************
*** 2951,2957 **** RestoreArchivedFile(char *path, const char *xlogfname,
  	 * of log segments that weren't yet transferred to the archive.
  	 *
  	 * Notice that we don't actually overwrite any files when we copy back
! 	 * from archive because the recoveryRestoreCommand may inadvertently
  	 * restore inappropriate xlogs, or they may be corrupt, so we may wish to
  	 * fallback to the segments remaining in current XLOGDIR later. The
  	 * copy-from-archive filename is always the same, ensuring that we don't
--- 2951,2957 ----
  	 * of log segments that weren't yet transferred to the archive.
  	 *
  	 * Notice that we don't actually overwrite any files when we copy back
! 	 * from archive because the restore_command may inadvertently
  	 * restore inappropriate xlogs, or they may be corrupt, so we may wish to
  	 * fallback to the segments remaining in current XLOGDIR later. The
  	 * copy-from-archive filename is always the same, ensuring that we don't
***************
*** 3015,3021 **** RestoreArchivedFile(char *path, const char *xlogfname,
  	endp = xlogRestoreCmd + MAXPGPATH - 1;
  	*endp = '\0';
  
! 	for (sp = recoveryRestoreCommand; *sp; sp++)
  	{
  		if (*sp == '%')
  		{
--- 3015,3021 ----
  	endp = xlogRestoreCmd + MAXPGPATH - 1;
  	*endp = '\0';
  
! 	for (sp = restore_command; *sp; sp++)
  	{
  		if (*sp == '%')
  		{
***************
*** 3106,3112 **** RestoreArchivedFile(char *path, const char *xlogfname,
  				 * incorrectly conclude we've reached the end of WAL and we're
  				 * done recovering ...
  				 */
! 				if (StandbyMode && stat_buf.st_size < expectedSize)
  					elevel = DEBUG1;
  				else
  					elevel = FATAL;
--- 3106,3112 ----
  				 * incorrectly conclude we've reached the end of WAL and we're
  				 * done recovering ...
  				 */
! 				if (standby_mode && stat_buf.st_size < expectedSize)
  					elevel = DEBUG1;
  				else
  					elevel = FATAL;
***************
*** 4063,4069 **** next_record_is_invalid:
  	}
  
  	/* In standby-mode, keep trying */
! 	if (StandbyMode)
  		goto retry;
  	else
  		return NULL;
--- 4063,4069 ----
  	}
  
  	/* In standby-mode, keep trying */
! 	if (standby_mode)
  		goto retry;
  	else
  		return NULL;
***************
*** 4522,4528 **** writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
  	 * Write comment to history file to explain why and where timeline
  	 * changed. Comment varies according to the recovery target used.
  	 */
! 	if (recoveryTarget == RECOVERY_TARGET_XID)
  		snprintf(buffer, sizeof(buffer),
  				 "%s%u\t%s\t%s transaction %u\n",
  				 (srcfd < 0) ? "" : "\n",
--- 4522,4528 ----
  	 * Write comment to history file to explain why and where timeline
  	 * changed. Comment varies according to the recovery target used.
  	 */
! 	if (recoveryStopTarget == RECOVERY_TARGET_XID)
  		snprintf(buffer, sizeof(buffer),
  				 "%s%u\t%s\t%s transaction %u\n",
  				 (srcfd < 0) ? "" : "\n",
***************
*** 4530,4536 **** writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
  				 xlogfname,
  				 recoveryStopAfter ? "after" : "before",
  				 recoveryStopXid);
! 	else if (recoveryTarget == RECOVERY_TARGET_TIME)
  		snprintf(buffer, sizeof(buffer),
  				 "%s%u\t%s\t%s %s\n",
  				 (srcfd < 0) ? "" : "\n",
--- 4530,4536 ----
  				 xlogfname,
  				 recoveryStopAfter ? "after" : "before",
  				 recoveryStopXid);
! 	else if (recoveryStopTarget == RECOVERY_TARGET_TIME)
  		snprintf(buffer, sizeof(buffer),
  				 "%s%u\t%s\t%s %s\n",
  				 (srcfd < 0) ? "" : "\n",
***************
*** 4538,4544 **** writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
  				 xlogfname,
  				 recoveryStopAfter ? "after" : "before",
  				 timestamptz_to_str(recoveryStopTime));
! 	else if (recoveryTarget == RECOVERY_TARGET_NAME)
  		snprintf(buffer, sizeof(buffer),
  				 "%s%u\t%s\tat restore point \"%s\"\n",
  				 (srcfd < 0) ? "" : "\n",
--- 4538,4544 ----
  				 xlogfname,
  				 recoveryStopAfter ? "after" : "before",
  				 timestamptz_to_str(recoveryStopTime));
! 	else if (recoveryStopTarget == RECOVERY_TARGET_NAME)
  		snprintf(buffer, sizeof(buffer),
  				 "%s%u\t%s\tat restore point \"%s\"\n",
  				 (srcfd < 0) ? "" : "\n",
***************
*** 5276,5283 **** static void
  readRecoveryCommandFile(void)
  {
  	FILE	   *fd;
- 	TimeLineID	rtli = 0;
- 	bool		rtliGiven = false;
  	ConfigVariable *item,
  			   *head = NULL,
  			   *tail = NULL;
--- 5276,5281 ----
***************
*** 5302,5480 **** readRecoveryCommandFile(void)
  	for (item = head; item; item = item->next)
  	{
  		if (strcmp(item->name, "restore_command") == 0)
! 		{
! 			recoveryRestoreCommand = pstrdup(item->value);
! 			ereport(DEBUG2,
! 					(errmsg_internal("restore_command = '%s'",
! 									 recoveryRestoreCommand)));
! 		}
  		else if (strcmp(item->name, "recovery_end_command") == 0)
! 		{
! 			recoveryEndCommand = pstrdup(item->value);
! 			ereport(DEBUG2,
! 					(errmsg_internal("recovery_end_command = '%s'",
! 									 recoveryEndCommand)));
! 		}
  		else if (strcmp(item->name, "archive_cleanup_command") == 0)
! 		{
! 			archiveCleanupCommand = pstrdup(item->value);
! 			ereport(DEBUG2,
! 					(errmsg_internal("archive_cleanup_command = '%s'",
! 									 archiveCleanupCommand)));
! 		}
  		else if (strcmp(item->name, "pause_at_recovery_target") == 0)
! 		{
! 			if (!parse_bool(item->value, &recoveryPauseAtTarget))
! 				ereport(ERROR,
! 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 						 errmsg("parameter \"%s\" requires a Boolean value", "pause_at_recovery_target")));
! 			ereport(DEBUG2,
! 					(errmsg_internal("pause_at_recovery_target = '%s'",
! 									 item->value)));
! 		}
  		else if (strcmp(item->name, "recovery_target_timeline") == 0)
! 		{
! 			rtliGiven = true;
! 			if (strcmp(item->value, "latest") == 0)
! 				rtli = 0;
! 			else
! 			{
! 				errno = 0;
! 				rtli = (TimeLineID) strtoul(item->value, NULL, 0);
! 				if (errno == EINVAL || errno == ERANGE)
! 					ereport(FATAL,
! 							(errmsg("recovery_target_timeline is not a valid number: \"%s\"",
! 									item->value)));
! 			}
! 			if (rtli)
! 				ereport(DEBUG2,
! 						(errmsg_internal("recovery_target_timeline = %u", rtli)));
! 			else
! 				ereport(DEBUG2,
! 						(errmsg_internal("recovery_target_timeline = latest")));
! 		}
  		else if (strcmp(item->name, "recovery_target_xid") == 0)
! 		{
! 			errno = 0;
! 			recoveryTargetXid = (TransactionId) strtoul(item->value, NULL, 0);
! 			if (errno == EINVAL || errno == ERANGE)
! 				ereport(FATAL,
! 				 (errmsg("recovery_target_xid is not a valid number: \"%s\"",
! 						 item->value)));
! 			ereport(DEBUG2,
! 					(errmsg_internal("recovery_target_xid = %u",
! 							 		 recoveryTargetXid)));
! 			recoveryTarget = RECOVERY_TARGET_XID;
! 		}
  		else if (strcmp(item->name, "recovery_target_time") == 0)
! 		{
! 			/*
! 			 * if recovery_target_xid or recovery_target_name specified, then
! 			 * this overrides recovery_target_time
! 			 */
! 			if (recoveryTarget == RECOVERY_TARGET_XID ||
! 				recoveryTarget == RECOVERY_TARGET_NAME)
! 				continue;
! 			recoveryTarget = RECOVERY_TARGET_TIME;
! 
! 			/*
! 			 * Convert the time string given by the user to TimestampTz form.
! 			 */
! 			recoveryTargetTime =
! 				DatumGetTimestampTz(DirectFunctionCall3(timestamptz_in,
! 												CStringGetDatum(item->value),
! 												ObjectIdGetDatum(InvalidOid),
! 														Int32GetDatum(-1)));
! 			ereport(DEBUG2,
! 					(errmsg_internal("recovery_target_time = '%s'",
! 							 		 timestamptz_to_str(recoveryTargetTime))));
! 		}
  		else if (strcmp(item->name, "recovery_target_name") == 0)
! 		{
! 			/*
! 			 * if recovery_target_xid specified, then this overrides
! 			 * recovery_target_name
! 			 */
! 			if (recoveryTarget == RECOVERY_TARGET_XID)
! 				continue;
! 			recoveryTarget = RECOVERY_TARGET_NAME;
! 
! 			recoveryTargetName = pstrdup(item->value);
! 			if (strlen(recoveryTargetName) >= MAXFNAMELEN)
! 				ereport(FATAL,
! 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 						 errmsg("recovery_target_name is too long (maximum %d characters)",
! 								MAXFNAMELEN - 1)));
! 
! 			ereport(DEBUG2,
! 					(errmsg_internal("recovery_target_name = '%s'",
! 									 recoveryTargetName)));
! 		}
  		else if (strcmp(item->name, "recovery_target_inclusive") == 0)
! 		{
! 			/*
! 			 * does nothing if a recovery_target is not also set
! 			 */
! 			if (!parse_bool(item->value, &recoveryTargetInclusive))
! 				ereport(ERROR,
! 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 						 errmsg("parameter \"%s\" requires a Boolean value",
! 								"recovery_target_inclusive")));
! 			ereport(DEBUG2,
! 					(errmsg_internal("recovery_target_inclusive = %s",
! 									 item->value)));
! 		}
  		else if (strcmp(item->name, "standby_mode") == 0)
! 		{
! 			if (!parse_bool(item->value, &StandbyMode))
! 				ereport(ERROR,
! 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 						 errmsg("parameter \"%s\" requires a Boolean value",
! 								"standby_mode")));
! 			ereport(DEBUG2,
! 					(errmsg_internal("standby_mode = '%s'", item->value)));
! 		}
  		else if (strcmp(item->name, "primary_conninfo") == 0)
! 		{
! 			PrimaryConnInfo = pstrdup(item->value);
! 			ereport(DEBUG2,
! 					(errmsg_internal("primary_conninfo = '%s'",
! 									 PrimaryConnInfo)));
! 		}
  		else if (strcmp(item->name, "trigger_file") == 0)
! 		{
! 			TriggerFile = pstrdup(item->value);
! 			ereport(DEBUG2,
! 					(errmsg_internal("trigger_file = '%s'",
! 									 TriggerFile)));
! 		}
  		else
  			ereport(FATAL,
  					(errmsg("unrecognized recovery parameter \"%s\"",
  							item->name)));
  	}
  
  	/*
  	 * Check for compulsory parameters
  	 */
! 	if (StandbyMode)
! 	{
! 		if (PrimaryConnInfo == NULL && recoveryRestoreCommand == NULL)
! 			ereport(WARNING,
! 					(errmsg("recovery command file \"%s\" specified neither primary_conninfo nor restore_command",
! 							RECOVERY_COMMAND_FILE),
! 					 errhint("The database server will regularly poll the pg_xlog subdirectory to check for files placed there.")));
! 	}
! 	else
! 	{
! 		if (recoveryRestoreCommand == NULL)
! 			ereport(FATAL,
! 					(errmsg("recovery command file \"%s\" must specify restore_command when standby mode is not enabled",
! 							RECOVERY_COMMAND_FILE)));
! 	}
! 
! 	/* Enable fetching from archive recovery area */
! 	InArchiveRecovery = true;
  
  	/*
  	 * If user specified recovery_target_timeline, validate it or compute the
--- 5300,5346 ----
  	for (item = head; item; item = item->next)
  	{
  		if (strcmp(item->name, "restore_command") == 0)
! 			SetConfigOption("restore_command", item->value, PGC_SIGHUP, PGC_S_OVERRIDE);
  		else if (strcmp(item->name, "recovery_end_command") == 0)
! 			SetConfigOption("recovery_end_command", item->value, PGC_SIGHUP, PGC_S_OVERRIDE);
  		else if (strcmp(item->name, "archive_cleanup_command") == 0)
! 			SetConfigOption("archive_cleanup_command", item->value, PGC_SIGHUP, PGC_S_OVERRIDE);
  		else if (strcmp(item->name, "pause_at_recovery_target") == 0)
! 			SetConfigOption("pause_at_recovery_target", item->value, PGC_SIGHUP, PGC_S_OVERRIDE);
  		else if (strcmp(item->name, "recovery_target_timeline") == 0)
! 			SetConfigOption("recovery_target_timeline", item->value, PGC_POSTMASTER, PGC_S_OVERRIDE);
  		else if (strcmp(item->name, "recovery_target_xid") == 0)
! 			SetConfigOption("recovery_target_xid", item->value, PGC_SIGHUP, PGC_S_OVERRIDE);
  		else if (strcmp(item->name, "recovery_target_time") == 0)
! 			SetConfigOption("recovery_target_time", item->value, PGC_SIGHUP, PGC_S_OVERRIDE);
  		else if (strcmp(item->name, "recovery_target_name") == 0)
! 			SetConfigOption("recovery_target_name", item->value, PGC_SIGHUP, PGC_S_OVERRIDE);
  		else if (strcmp(item->name, "recovery_target_inclusive") == 0)
! 			SetConfigOption("recovery_target_inclusive", item->value, PGC_SIGHUP, PGC_S_OVERRIDE);
  		else if (strcmp(item->name, "standby_mode") == 0)
! 			SetConfigOption("standby_mode", item->value, PGC_POSTMASTER, PGC_S_OVERRIDE);
  		else if (strcmp(item->name, "primary_conninfo") == 0)
! 			SetConfigOption("primary_conninfo", item->value, PGC_SIGHUP, PGC_S_OVERRIDE);
  		else if (strcmp(item->name, "trigger_file") == 0)
! 			SetConfigOption("trigger_file", item->value, PGC_SIGHUP, PGC_S_OVERRIDE);
  		else
  			ereport(FATAL,
  					(errmsg("unrecognized recovery parameter \"%s\"",
  							item->name)));
  	}
  
+ 	/* Enable fetching from archive recovery area */
+ 	InArchiveRecovery = true;
+ 
  	/*
  	 * Check for compulsory parameters
  	 */
! 	if (standby_mode && !restore_command[0] && !primary_conninfo[0])
! 		ereport(WARNING,
! 				(errmsg("neither primary_conninfo nor restore_command is specified"),
! 				 errhint("The database server will regularly poll the pg_xlog subdirectory to "
! 						 "check for files placed there until either of them is set in postgresql.conf.")));
! 	CheckRestoreCommandSet();
  
  	/*
  	 * If user specified recovery_target_timeline, validate it or compute the
***************
*** 5482,5497 **** readRecoveryCommandFile(void)
  	 * command and set InArchiveRecovery, because we need to fetch timeline
  	 * history files from the archive.
  	 */
! 	if (rtliGiven)
  	{
! 		if (rtli)
  		{
  			/* Timeline 1 does not have a history file, all else should */
! 			if (rtli != 1 && !existsTimeLineHistory(rtli))
  				ereport(FATAL,
  						(errmsg("recovery target timeline %u does not exist",
! 								rtli)));
! 			recoveryTargetTLI = rtli;
  			recoveryTargetIsLatest = false;
  		}
  		else
--- 5348,5363 ----
  	 * command and set InArchiveRecovery, because we need to fetch timeline
  	 * history files from the archive.
  	 */
! 	if (strcmp(recovery_target_timeline_string, "") != 0)
  	{
! 		if (recovery_target_timeline)
  		{
  			/* Timeline 1 does not have a history file, all else should */
! 			if (recovery_target_timeline != 1 && !existsTimeLineHistory(recovery_target_timeline))
  				ereport(FATAL,
  						(errmsg("recovery target timeline %u does not exist",
! 								recovery_target_timeline)));
! 			recoveryTargetTLI = recovery_target_timeline;
  			recoveryTargetIsLatest = false;
  		}
  		else
***************
*** 5646,5652 **** recoveryStopsHere(XLogRecord *record, bool *includeThis)
  		return false;
  
  	/* Do we have a PITR target at all? */
! 	if (recoveryTarget == RECOVERY_TARGET_UNSET)
  	{
  		/*
  		 * Save timestamp of latest transaction commit/abort if this is a
--- 5512,5518 ----
  		return false;
  
  	/* Do we have a PITR target at all? */
! 	if (recovery_target == RECOVERY_TARGET_UNSET)
  	{
  		/*
  		 * Save timestamp of latest transaction commit/abort if this is a
***************
*** 5657,5663 **** recoveryStopsHere(XLogRecord *record, bool *includeThis)
  		return false;
  	}
  
! 	if (recoveryTarget == RECOVERY_TARGET_XID)
  	{
  		/*
  		 * There can be only one transaction end record with this exact
--- 5523,5529 ----
  		return false;
  	}
  
! 	if (recovery_target == RECOVERY_TARGET_XID)
  	{
  		/*
  		 * There can be only one transaction end record with this exact
***************
*** 5668,5687 **** recoveryStopsHere(XLogRecord *record, bool *includeThis)
  		 * they complete. A higher numbered xid will complete before you about
  		 * 50% of the time...
  		 */
! 		stopsHere = (record->xl_xid == recoveryTargetXid);
  		if (stopsHere)
! 			*includeThis = recoveryTargetInclusive;
  	}
! 	else if (recoveryTarget == RECOVERY_TARGET_NAME)
  	{
  		/*
  		 * There can be many restore points that share the same name, so we
  		 * stop at the first one
  		 */
! 		stopsHere = (strcmp(recordRPName, recoveryTargetName) == 0);
  
  		/*
! 		 * Ignore recoveryTargetInclusive because this is not a transaction
  		 * record
  		 */
  		*includeThis = false;
--- 5534,5553 ----
  		 * they complete. A higher numbered xid will complete before you about
  		 * 50% of the time...
  		 */
! 		stopsHere = (record->xl_xid == recovery_target_xid);
  		if (stopsHere)
! 			*includeThis = recovery_target_inclusive;
  	}
! 	else if (recovery_target == RECOVERY_TARGET_NAME)
  	{
  		/*
  		 * There can be many restore points that share the same name, so we
  		 * stop at the first one
  		 */
! 		stopsHere = (strcmp(recordRPName, recovery_target_name) == 0);
  
  		/*
! 		 * Ignore recovery_target_inclusive because this is not a transaction
  		 * record
  		 */
  		*includeThis = false;
***************
*** 5693,5708 **** recoveryStopsHere(XLogRecord *record, bool *includeThis)
  		 * we stop after the last one, if we are inclusive, or stop at the
  		 * first one if we are exclusive
  		 */
! 		if (recoveryTargetInclusive)
! 			stopsHere = (recordXtime > recoveryTargetTime);
  		else
! 			stopsHere = (recordXtime >= recoveryTargetTime);
  		if (stopsHere)
  			*includeThis = false;
  	}
  
  	if (stopsHere)
  	{
  		recoveryStopXid = record->xl_xid;
  		recoveryStopTime = recordXtime;
  		recoveryStopAfter = *includeThis;
--- 5559,5575 ----
  		 * we stop after the last one, if we are inclusive, or stop at the
  		 * first one if we are exclusive
  		 */
! 		if (recovery_target_inclusive)
! 			stopsHere = (recordXtime > recovery_target_time);
  		else
! 			stopsHere = (recordXtime >= recovery_target_time);
  		if (stopsHere)
  			*includeThis = false;
  	}
  
  	if (stopsHere)
  	{
+ 		recoveryStopTarget = recovery_target;
  		recoveryStopXid = record->xl_xid;
  		recoveryStopTime = recordXtime;
  		recoveryStopAfter = *includeThis;
***************
*** 6003,6008 **** CheckRequiredParameterValues(void)
--- 5870,5888 ----
  }
  
  /*
+  * Check to see if restore_command must be set for archive recovery
+  * when standby mode is not enabled
+  */
+ static void
+ CheckRestoreCommandSet(void)
+ {
+ 	if (InArchiveRecovery && !standby_mode && !restore_command[0])
+ 		ereport(FATAL,
+ 				(errmsg("restore_command must be specified for archive recovery "
+ 						"when standby mode is not enabled")));
+ }
+ 
+ /*
   * This must be called ONCE during postmaster or standalone-backend startup
   */
  void
***************
*** 6122,6148 **** StartupXLOG(void)
  	 * see them
  	 */
  	XLogCtl->RecoveryTargetTLI = recoveryTargetTLI;
! 	strncpy(XLogCtl->archiveCleanupCommand,
! 			archiveCleanupCommand ? archiveCleanupCommand : "",
! 			sizeof(XLogCtl->archiveCleanupCommand));
  
  	if (InArchiveRecovery)
  	{
! 		if (StandbyMode)
  			ereport(LOG,
  					(errmsg("entering standby mode")));
- 		else if (recoveryTarget == RECOVERY_TARGET_XID)
- 			ereport(LOG,
- 					(errmsg("starting point-in-time recovery to XID %u",
- 							recoveryTargetXid)));
- 		else if (recoveryTarget == RECOVERY_TARGET_TIME)
- 			ereport(LOG,
- 					(errmsg("starting point-in-time recovery to %s",
- 							timestamptz_to_str(recoveryTargetTime))));
- 		else if (recoveryTarget == RECOVERY_TARGET_NAME)
- 			ereport(LOG,
- 					(errmsg("starting point-in-time recovery to \"%s\"",
- 							recoveryTargetName)));
  		else
  			ereport(LOG,
  					(errmsg("starting archive recovery")));
--- 6002,6016 ----
  	 * see them
  	 */
  	XLogCtl->RecoveryTargetTLI = recoveryTargetTLI;
! 	strncpy(XLogCtl->archive_cleanup_command,
! 			archive_cleanup_command,
! 			sizeof(XLogCtl->archive_cleanup_command));
  
  	if (InArchiveRecovery)
  	{
! 		if (standby_mode)
  			ereport(LOG,
  					(errmsg("entering standby mode")));
  		else
  			ereport(LOG,
  					(errmsg("starting archive recovery")));
***************
*** 6152,6158 **** StartupXLOG(void)
  	 * Take ownership of the wakeup latch if we're going to sleep during
  	 * recovery.
  	 */
! 	if (StandbyMode)
  		OwnLatch(&XLogCtl->recoveryWakeupLatch);
  
  	if (read_backup_label(&checkPointLoc, &backupEndRequired))
--- 6020,6026 ----
  	 * Take ownership of the wakeup latch if we're going to sleep during
  	 * recovery.
  	 */
! 	if (standby_mode)
  		OwnLatch(&XLogCtl->recoveryWakeupLatch);
  
  	if (read_backup_label(&checkPointLoc, &backupEndRequired))
***************
*** 6210,6216 **** StartupXLOG(void)
  					(errmsg("checkpoint record is at %X/%X",
  							checkPointLoc.xlogid, checkPointLoc.xrecoff)));
  		}
! 		else if (StandbyMode)
  		{
  			/*
  			 * The last valid checkpoint record required for a streaming
--- 6078,6084 ----
  					(errmsg("checkpoint record is at %X/%X",
  							checkPointLoc.xlogid, checkPointLoc.xrecoff)));
  		}
! 		else if (standby_mode)
  		{
  			/*
  			 * The last valid checkpoint record required for a streaming
***************
*** 6563,6569 **** StartupXLOG(void)
  					 * Pause only if users can connect to send a resume
  					 * message
  					 */
! 					if (recoveryPauseAtTarget && standbyState == STANDBY_SNAPSHOT_READY)
  					{
  						SetRecoveryPause(true);
  						recoveryPausesHere();
--- 6431,6437 ----
  					 * Pause only if users can connect to send a resume
  					 * message
  					 */
! 					if (pause_at_recovery_target && standbyState == STANDBY_SNAPSHOT_READY)
  					{
  						SetRecoveryPause(true);
  						recoveryPausesHere();
***************
*** 6662,6668 **** StartupXLOG(void)
  	 * We don't need the latch anymore. It's not strictly necessary to disown
  	 * it, but let's do it for the sake of tidiness.
  	 */
! 	if (StandbyMode)
  		DisownLatch(&XLogCtl->recoveryWakeupLatch);
  
  	/*
--- 6530,6536 ----
  	 * We don't need the latch anymore. It's not strictly necessary to disown
  	 * it, but let's do it for the sake of tidiness.
  	 */
! 	if (standby_mode)
  		DisownLatch(&XLogCtl->recoveryWakeupLatch);
  
  	/*
***************
*** 6670,6676 **** StartupXLOG(void)
  	 * recovery to force fetching the files (which would be required at end of
  	 * recovery, e.g., timeline history file) from archive or pg_xlog.
  	 */
! 	StandbyMode = false;
  
  	/*
  	 * Re-fetch the last valid or last applied record, so we can identify the
--- 6538,6544 ----
  	 * recovery to force fetching the files (which would be required at end of
  	 * recovery, e.g., timeline history file) from archive or pg_xlog.
  	 */
! 	SetConfigOption("standby_mode", "false", PGC_POSTMASTER, PGC_S_OVERRIDE);
  
  	/*
  	 * Re-fetch the last valid or last applied record, so we can identify the
***************
*** 6863,6870 **** StartupXLOG(void)
  		/*
  		 * And finally, execute the recovery_end_command, if any.
  		 */
! 		if (recoveryEndCommand)
! 			ExecuteRecoveryCommand(recoveryEndCommand,
  								   "recovery_end_command",
  								   true);
  	}
--- 6731,6738 ----
  		/*
  		 * And finally, execute the recovery_end_command, if any.
  		 */
! 		if (recovery_end_command[0])
! 			ExecuteRecoveryCommand(recovery_end_command,
  								   "recovery_end_command",
  								   true);
  	}
***************
*** 8187,8194 **** CreateRestartPoint(int flags)
  	/*
  	 * Finally, execute archive_cleanup_command, if any.
  	 */
! 	if (XLogCtl->archiveCleanupCommand[0])
! 		ExecuteRecoveryCommand(XLogCtl->archiveCleanupCommand,
  							   "archive_cleanup_command",
  							   false);
  
--- 8055,8062 ----
  	/*
  	 * Finally, execute archive_cleanup_command, if any.
  	 */
! 	if (XLogCtl->archive_cleanup_command[0])
! 		ExecuteRecoveryCommand(XLogCtl->archive_cleanup_command,
  							   "archive_cleanup_command",
  							   false);
  
***************
*** 10019,10024 **** HandleStartupProcInterrupts(void)
--- 9887,9903 ----
  	{
  		got_SIGHUP = false;
  		ProcessConfigFile(PGC_SIGHUP);
+ 
+ 		/* Check for compulsory parameter */
+ 		CheckRestoreCommandSet();
+ 
+ 		/*
+ 		 * If primary_conninfo has been changed while walreceiver
+ 		 * is running, stop walreceiver so that it restarts replication
+ 		 * using new primary_conninfo.
+ 		 */
+ 		if (IsPrimaryConninfoChanged() && WalRcvInProgress())
+ 			ShutdownWalRcv();
  	}
  
  	/*
***************
*** 10143,10149 **** XLogPageRead(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt,
  		 * Signal bgwriter to start a restartpoint if we've replayed too much
  		 * xlog since the last one.
  		 */
! 		if (StandbyMode && bgwriterLaunched)
  		{
  			if (XLogCheckpointNeeded(readId, readSeg))
  			{
--- 10022,10028 ----
  		 * Signal bgwriter to start a restartpoint if we've replayed too much
  		 * xlog since the last one.
  		 */
! 		if (standby_mode && bgwriterLaunched)
  		{
  			if (XLogCheckpointNeeded(readId, readSeg))
  			{
***************
*** 10165,10171 **** retry:
  	if (readFile < 0 ||
  		(readSource == XLOG_FROM_STREAM && !XLByteLT(*RecPtr, receivedUpto)))
  	{
! 		if (StandbyMode)
  		{
  			/*
  			 * In standby mode, wait for the requested record to become
--- 10044,10050 ----
  	if (readFile < 0 ||
  		(readSource == XLOG_FROM_STREAM && !XLByteLT(*RecPtr, receivedUpto)))
  	{
! 		if (standby_mode)
  		{
  			/*
  			 * In standby mode, wait for the requested record to become
***************
*** 10329,10339 **** retry:
  						 * backwards to start redo at RedoStartLSN, we will
  						 * have the logs streamed already.
  						 */
! 						if (PrimaryConnInfo)
  						{
  							RequestXLogStreaming(
  									  fetching_ckpt ? RedoStartLSN : *RecPtr,
! 												 PrimaryConnInfo);
  							continue;
  						}
  					}
--- 10208,10218 ----
  						 * backwards to start redo at RedoStartLSN, we will
  						 * have the logs streamed already.
  						 */
! 						if (primary_conninfo[0])
  						{
  							RequestXLogStreaming(
  									  fetching_ckpt ? RedoStartLSN : *RecPtr,
! 												 primary_conninfo);
  							continue;
  						}
  					}
***************
*** 10476,10482 **** next_record_is_invalid:
  	readSource = 0;
  
  	/* In standby-mode, keep trying */
! 	if (StandbyMode)
  		goto retry;
  	else
  		return false;
--- 10355,10361 ----
  	readSource = 0;
  
  	/* In standby-mode, keep trying */
! 	if (standby_mode)
  		goto retry;
  	else
  		return false;
***************
*** 10548,10562 **** CheckForStandbyTrigger(void)
  		return true;
  	}
  
! 	if (TriggerFile == NULL)
  		return false;
  
! 	if (stat(TriggerFile, &stat_buf) == 0)
  	{
  		ereport(LOG,
! 				(errmsg("trigger file found: %s", TriggerFile)));
  		ShutdownWalRcv();
! 		unlink(TriggerFile);
  		triggered = true;
  		return true;
  	}
--- 10427,10441 ----
  		return true;
  	}
  
! 	if (!trigger_file[0])
  		return false;
  
! 	if (stat(trigger_file, &stat_buf) == 0)
  	{
  		ereport(LOG,
! 				(errmsg("trigger file found: %s", trigger_file)));
  		ShutdownWalRcv();
! 		unlink(trigger_file);
  		triggered = true;
  		return true;
  	}
*** a/src/backend/replication/walreceiverfuncs.c
--- b/src/backend/replication/walreceiverfuncs.c
***************
*** 109,114 **** WalRcvInProgress(void)
--- 109,131 ----
  }
  
  /*
+  * Is the current primary_conninfo different from that which walreceiver is using?
+  */
+ bool
+ IsPrimaryConninfoChanged(void)
+ {
+ 	/* use volatile pointer to prevent code rearrangement */
+ 	volatile WalRcvData *walrcv = WalRcv;
+ 	char		conninfo[MAXCONNINFO];
+ 
+ 	SpinLockAcquire(&walrcv->mutex);
+ 	strlcpy(conninfo, (char *) walrcv->conninfo, MAXCONNINFO);
+ 	SpinLockRelease(&walrcv->mutex);
+ 
+ 	return strncmp(conninfo, primary_conninfo, MAXCONNINFO) != 0;
+ }
+ 
+ /*
   * Stop walreceiver (if running) and wait for it to die.
   */
  void
*** a/src/backend/utils/misc/guc.c
--- b/src/backend/utils/misc/guc.c
***************
*** 30,35 ****
--- 30,36 ----
  #include "access/transam.h"
  #include "access/twophase.h"
  #include "access/xact.h"
+ #include "access/xlog_internal.h"
  #include "catalog/namespace.h"
  #include "commands/async.h"
  #include "commands/prepare.h"
***************
*** 205,210 **** static bool check_application_name(char **newval, void **extra, GucSource source
--- 206,219 ----
  static void assign_application_name(const char *newval, void *extra);
  static const char *show_unix_socket_permissions(void);
  static const char *show_log_file_mode(void);
+ static bool check_recovery_target_xid(char **newval, void **extra, GucSource source);
+ static void assign_recovery_target_xid(const char *newval, void *extra);
+ static bool check_recovery_target_name(char **newval, void **extra, GucSource source);
+ static void assign_recovery_target_name(const char *newval, void *extra);
+ static bool check_recovery_target_time(char **newval, void **extra, GucSource source);
+ static void assign_recovery_target_time(const char *newval, void *extra);
+ static bool check_recovery_target_timeline(char **newval, void **extra, GucSource source);
+ static void assign_recovery_target_timeline(const char *newval, void *extra);
  
  static char *config_enum_get_options(struct config_enum * record,
  						const char *prefix, const char *suffix,
***************
*** 476,481 **** static int	wal_block_size;
--- 485,492 ----
  static int	wal_segment_size;
  static bool integer_datetimes;
  static int	effective_io_concurrency;
+ static char *recovery_target_xid_string;
+ static char *recovery_target_time_string;
  
  /* should be static, but commands/variable.c needs to get at this */
  char	   *role_string;
***************
*** 555,560 **** const char *const config_group_names[] =
--- 566,575 ----
  	gettext_noop("Write-Ahead Log / Checkpoints"),
  	/* WAL_ARCHIVING */
  	gettext_noop("Write-Ahead Log / Archiving"),
+ 	/* WAL_ARCHIVE_RECOVERY */
+ 	gettext_noop("Write-Ahead Log / Archive Recovery"),
+ 	/* WAL_RECOVERY_TARGET */
+ 	gettext_noop("Write-Ahead Log / Recovery Target"),
  	/* REPLICATION */
  	gettext_noop("Replication"),
  	/* REPLICATION_SENDING */
***************
*** 1365,1370 **** static struct config_bool ConfigureNamesBool[] =
--- 1380,1415 ----
  	},
  
  	{
+ 		{"recovery_target_inclusive", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+ 			gettext_noop("Sets whether to include or exclude transaction with recovery target."),
+ 			NULL
+ 		},
+ 		&recovery_target_inclusive,
+ 		true,
+ 		NULL, NULL, NULL
+ 	},
+ 
+ 	{
+ 		{"pause_at_recovery_target", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+ 			gettext_noop("Sets whether recovery should pause when the recovery target is reached."),
+ 			NULL
+ 		},
+ 		&pause_at_recovery_target,
+ 		true,
+ 		NULL, NULL, NULL
+ 	},
+ 
+ 	{
+ 		{"standby_mode", PGC_POSTMASTER, REPLICATION_STANDBY,
+ 			gettext_noop("Sets whether to start the server as a standby."),
+ 			NULL
+ 		},
+ 		&standby_mode,
+ 		false,
+ 		NULL, NULL, NULL
+ 	},
+ 
+ 	{
  		{"hot_standby", PGC_POSTMASTER, REPLICATION_STANDBY,
  			gettext_noop("Allows connections and queries during recovery."),
  			NULL
***************
*** 2521,2526 **** static struct config_string ConfigureNamesString[] =
--- 2566,2661 ----
  	},
  
  	{
+ 		{"restore_command", PGC_SIGHUP, WAL_ARCHIVE_RECOVERY,
+ 			gettext_noop("Sets the shell command that will retrieve an archived WAL file."),
+ 			NULL
+ 		},
+ 		&restore_command,
+ 		"",
+ 		NULL, NULL, NULL
+ 	},
+ 
+ 	{
+ 		{"archive_cleanup_command", PGC_SIGHUP, WAL_ARCHIVE_RECOVERY,
+ 			gettext_noop("Sets the shell command that will be executed at every restartpoint."),
+ 			NULL
+ 		},
+ 		&archive_cleanup_command,
+ 		"",
+ 		NULL, NULL, NULL
+ 	},
+ 
+ 	{
+ 		{"recovery_end_command", PGC_SIGHUP, WAL_ARCHIVE_RECOVERY,
+ 			gettext_noop("Sets the shell command that will be executed once only at the end of recovery."),
+ 			NULL
+ 		},
+ 		&recovery_end_command,
+ 		"",
+ 		NULL, NULL, NULL
+ 	},
+ 
+ 	{
+ 		{"recovery_target_xid", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+ 			gettext_noop("Sets the transaction ID up to which recovery will proceed."),
+ 			NULL
+ 		},
+ 		&recovery_target_xid_string,
+ 		"",
+ 		check_recovery_target_xid, assign_recovery_target_xid, NULL
+ 	},
+ 
+ 	{
+ 		{"recovery_target_name", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+ 			gettext_noop("Sets the named restore point."),
+ 			NULL
+ 		},
+ 		&recovery_target_name,
+ 		"",
+ 		check_recovery_target_name, assign_recovery_target_name, NULL
+ 	},
+ 
+ 	{
+ 		{"recovery_target_time", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+ 			gettext_noop("Sets the time stamp up to which recovery will proceed."),
+ 			NULL
+ 		},
+ 		&recovery_target_time_string,
+ 		"",
+ 		check_recovery_target_time, assign_recovery_target_time, NULL
+ 	},
+ 
+ 	{
+ 		{"recovery_target_timeline", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
+ 			gettext_noop("Sets recoverying into a particular timeline."),
+ 			NULL
+ 		},
+ 		&recovery_target_timeline_string,
+ 		"",
+ 		check_recovery_target_timeline, assign_recovery_target_timeline, NULL
+ 	},
+ 
+ 	{
+ 		{"primary_conninfo", PGC_SIGHUP, REPLICATION_STANDBY,
+ 			gettext_noop("Sets the connection string to be used to connect with the primary."),
+ 			NULL
+ 		},
+ 		&primary_conninfo,
+ 		"",
+ 		NULL, NULL, NULL
+ 	},
+ 
+ 	{
+ 		{"trigger_file", PGC_SIGHUP, REPLICATION_STANDBY,
+ 			gettext_noop("Sets the trigger file whose presence ends recovery in the standby."),
+ 			NULL
+ 		},
+ 		&trigger_file,
+ 		"",
+ 		NULL, NULL, NULL
+ 	},
+ 
+ 	{
  		{"client_encoding", PGC_USERSET, CLIENT_CONN_LOCALE,
  			gettext_noop("Sets the client's character set encoding."),
  			NULL,
***************
*** 8678,8681 **** show_log_file_mode(void)
--- 8813,8965 ----
  	return buf;
  }
  
+ static bool
+ check_recovery_target_xid(char **newval, void **extra, GucSource source)
+ {
+ 	TransactionId   xid;
+ 	TransactionId   *myextra;
+ 
+ 	errno = 0;
+ 	xid = (TransactionId) strtoul(*newval, NULL, 0);
+ 	if (errno == EINVAL || errno == ERANGE)
+ 	{
+ 		GUC_check_errdetail("recovery_target_xid is not a valid number: \"%s\"",
+ 							*newval);
+ 		return false;
+ 	}
+ 
+ 	myextra = (TransactionId *) guc_malloc(ERROR, sizeof(TransactionId));
+ 	*myextra = xid;
+ 	*extra = (void *) myextra;
+ 
+ 	return true;
+ }
+ 
+ static void
+ assign_recovery_target_xid(const char *newval, void *extra)
+ {
+ 	recovery_target_xid = *((TransactionId *) extra);
+ 
+ 	if (recovery_target_xid != InvalidTransactionId)
+ 		recovery_target = RECOVERY_TARGET_XID;
+ 	else if (recovery_target_name[0])
+ 		recovery_target = RECOVERY_TARGET_NAME;
+ 	else if (recovery_target_time != 0)
+ 		recovery_target = RECOVERY_TARGET_TIME;
+ 	else
+ 		recovery_target = RECOVERY_TARGET_UNSET;
+ }
+ 
+ static bool
+ check_recovery_target_name(char **newval, void **extra, GucSource source)
+ {
+ 	if (strlen(*newval) >= MAXFNAMELEN)
+ 	{
+ 		GUC_check_errdetail("\"recovery_target_name\" is too long (maximum %d characters)",
+ 							MAXFNAMELEN - 1);
+ 		return false;
+ 	}
+ 	return true;
+ }
+ 
+ static void
+ assign_recovery_target_name(const char *newval, void *extra)
+ {
+ 	if (recovery_target_xid != InvalidTransactionId)
+ 		recovery_target = RECOVERY_TARGET_XID;
+ 	else if (newval[0])
+ 		recovery_target = RECOVERY_TARGET_NAME;
+ 	else if (recovery_target_time != 0)
+ 		recovery_target = RECOVERY_TARGET_TIME;
+ 	else
+ 		recovery_target = RECOVERY_TARGET_UNSET;
+ }
+ 
+ static bool
+ check_recovery_target_time(char **newval, void **extra, GucSource source)
+ {
+ 	TimestampTz     time;
+ 	TimestampTz     *myextra;
+ 	MemoryContext oldcontext = CurrentMemoryContext;
+ 
+ 	PG_TRY();
+ 	{
+ 		time = (strcmp(*newval, "") == 0) ?
+ 			0 :
+ 			DatumGetTimestampTz(DirectFunctionCall3(timestamptz_in,
+ 													CStringGetDatum(*newval),
+ 													ObjectIdGetDatum(InvalidOid),
+ 													Int32GetDatum(-1)));
+ 	}
+ 	PG_CATCH();
+ 	{
+ 		ErrorData  *edata;
+ 
+ 		/* Save error info */
+ 		MemoryContextSwitchTo(oldcontext);
+ 		edata = CopyErrorData();
+ 		FlushErrorState();
+ 
+ 		/* Pass the error message */
+ 		GUC_check_errdetail("%s", edata->message);
+ 		FreeErrorData(edata);
+ 		return false;
+ 	}
+ 	PG_END_TRY();
+ 
+ 	myextra = (TimestampTz *) guc_malloc(ERROR, sizeof(TimestampTz));
+ 	*myextra = time;
+ 	*extra = (void *) myextra;
+ 
+ 	return true;
+ }
+ 
+ static void
+ assign_recovery_target_time(const char *newval, void *extra)
+ {
+ 	recovery_target_time = *((TimestampTz *) extra);
+ 
+ 	if (recovery_target_xid != InvalidTransactionId)
+ 		recovery_target = RECOVERY_TARGET_XID;
+ 	else if (recovery_target_name[0])
+ 		recovery_target = RECOVERY_TARGET_NAME;
+ 	else if (recovery_target_time != 0)
+ 		recovery_target = RECOVERY_TARGET_TIME;
+ 	else
+ 		recovery_target = RECOVERY_TARGET_UNSET;
+ }
+ 
+ static bool
+ check_recovery_target_timeline(char **newval, void **extra, GucSource source)
+ {
+ 	TimeLineID	tli = 0;
+ 	TimeLineID	*myextra;
+ 
+ 	if (strcmp(*newval, "latest") == 0)
+ 		tli = 0;
+ 	else
+ 	{
+ 		errno = 0;
+ 		tli = (TimeLineID) strtoul(*newval, NULL, 0);
+ 		if (errno == EINVAL || errno == ERANGE)
+ 		{
+ 			GUC_check_errdetail("recovery_target_timeline is not a valid number: \"%s\"",
+ 								*newval);
+ 			return false;
+ 		}
+ 	}
+ 
+ 	myextra = (TimeLineID *) guc_malloc(ERROR, sizeof(TimeLineID));
+ 	*myextra = tli;
+ 	*extra = (void *) myextra;
+ 
+ 	return true;
+ }
+ 
+ static void
+ assign_recovery_target_timeline(const char *newval, void *extra)
+ {
+ 	recovery_target_timeline = *((TimeLineID *) extra);
+ }
+ 
  #include "guc-file.c"
*** a/src/backend/utils/misc/postgresql.conf.sample
--- b/src/backend/utils/misc/postgresql.conf.sample
***************
*** 192,197 ****
--- 192,213 ----
  #archive_timeout = 0		# force a logfile segment switch after this
  				# number of seconds; 0 disables
  
+ # - Archive Recovery -
+ #restore_command = ''	# command to use to restore an archived logfile segment
+ 				# placeholders: %p = path of file to restore
+ 				#               %f = file name only
+ 				# e.g. 'cp /mnt/server/archivedir/%f %p'
+ #archive_cleanup_command = ''	# command to execute at every restartpoint
+ #recovery_end_command = ''	# command to execute at completion of recovery
+ 
+ # - Recovery Target -
+ #recovery_target_xid = ''
+ #recovery_target_name = ''
+ #recovery_target_time = ''
+ #recovery_target_inclusive = on
+ #pause_at_recovery_target = on
+ #recovery_target_timeline = ''
+ 
  
  #------------------------------------------------------------------------------
  # REPLICATION
***************
*** 219,224 ****
--- 235,244 ----
  
  # These settings are ignored on a master server
  
+ #standby_mode = off			# "on" starts the server as a standby
+ 					# (change requires restart)
+ #primary_conninfo = ''		# connection string to connect to the master
+ #trigger_file = ''		# trigger file to promote the standby
  #hot_standby = off			# "on" allows queries during recovery
  					# (change requires restart)
  #max_standby_archive_delay = 30s	# max delay before canceling queries
*** a/src/include/access/xlog.h
--- b/src/include/access/xlog.h
***************
*** 198,203 **** extern bool XLogArchiveMode;
--- 198,217 ----
  extern char *XLogArchiveCommand;
  extern bool EnableHotStandby;
  extern bool log_checkpoints;
+ extern char *restore_command;
+ extern char *archive_cleanup_command;
+ extern char *recovery_end_command;
+ extern bool standby_mode;
+ extern char *primary_conninfo;
+ extern char *trigger_file;
+ extern RecoveryTargetType recovery_target;
+ extern TransactionId recovery_target_xid;
+ extern TimestampTz recovery_target_time;
+ extern char *recovery_target_name;
+ extern bool recovery_target_inclusive;
+ extern bool pause_at_recovery_target;
+ extern char *recovery_target_timeline_string;
+ extern TimeLineID recovery_target_timeline;
  
  /* WAL levels */
  typedef enum WalLevel
*** a/src/include/replication/walreceiver.h
--- b/src/include/replication/walreceiver.h
***************
*** 110,115 **** extern Size WalRcvShmemSize(void);
--- 110,116 ----
  extern void WalRcvShmemInit(void);
  extern void ShutdownWalRcv(void);
  extern bool WalRcvInProgress(void);
+ extern bool IsPrimaryConninfoChanged(void);
  extern void RequestXLogStreaming(XLogRecPtr recptr, const char *conninfo);
  extern XLogRecPtr GetWalRcvWriteRecPtr(XLogRecPtr *latestChunkStart);
  
*** a/src/include/utils/guc_tables.h
--- b/src/include/utils/guc_tables.h
***************
*** 68,73 **** enum config_group
--- 68,75 ----
  	WAL_SETTINGS,
  	WAL_CHECKPOINTS,
  	WAL_ARCHIVING,
+ 	WAL_ARCHIVE_RECOVERY,
+ 	WAL_RECOVERY_TARGET,
  	REPLICATION,
  	REPLICATION_SENDING,
  	REPLICATION_MASTER,
