*** a/contrib/pg_archivecleanup/pg_archivecleanup.c
--- b/contrib/pg_archivecleanup/pg_archivecleanup.c
***************
*** 208,214 **** usage(void)
  	printf("  --help             show this help, then exit\n");
  	printf("  --version          output version information, then exit\n");
  	printf("\n"
! 		   "For use as archive_cleanup_command in recovery.conf when standby_mode = on:\n"
  		   "  archive_cleanup_command = 'pg_archivecleanup [OPTION]... ARCHIVELOCATION %%r'\n"
  		   "e.g.\n"
  		   "  archive_cleanup_command = 'pg_archivecleanup /mnt/server/archiverdir %%r'\n");
--- 208,214 ----
  	printf("  --help             show this help, then exit\n");
  	printf("  --version          output version information, then exit\n");
  	printf("\n"
! 		   "For use as archive_cleanup_command in postgresql.conf when standby_mode = on:\n"
  		   "  archive_cleanup_command = 'pg_archivecleanup [OPTION]... ARCHIVELOCATION %%r'\n"
  		   "e.g.\n"
  		   "  archive_cleanup_command = 'pg_archivecleanup /mnt/server/archiverdir %%r'\n");
*** a/contrib/pg_standby/pg_standby.c
--- b/contrib/pg_standby/pg_standby.c
***************
*** 531,537 **** usage(void)
  	printf("  --help             show this help, then exit\n");
  	printf("  --version          output version information, then exit\n");
  	printf("\n"
! 		   "Main intended use as restore_command in recovery.conf:\n"
  		   "  restore_command = 'pg_standby [OPTION]... ARCHIVELOCATION %%f %%p %%r'\n"
  		   "e.g.\n"
  	"  restore_command = 'pg_standby /mnt/server/archiverdir %%f %%p %%r'\n");
--- 531,537 ----
  	printf("  --help             show this help, then exit\n");
  	printf("  --version          output version information, then exit\n");
  	printf("\n"
! 		   "Main intended use as restore_command in postgresql.conf:\n"
  		   "  restore_command = 'pg_standby [OPTION]... ARCHIVELOCATION %%f %%p %%r'\n"
  		   "e.g.\n"
  	"  restore_command = 'pg_standby /mnt/server/archiverdir %%f %%p %%r'\n");
*** a/doc/src/sgml/backup.sgml
--- b/doc/src/sgml/backup.sgml
***************
*** 995,1002 **** SELECT pg_stop_backup();
     </listitem>
     <listitem>
      <para>
!      Create a recovery command file <filename>recovery.conf</> in the cluster
!      data directory (see <xref linkend="recovery-config">). You might
       also want to temporarily modify <filename>pg_hba.conf</> to prevent
       ordinary users from connecting until you are sure the recovery was successful.
      </para>
--- 995,1009 ----
     </listitem>
     <listitem>
      <para>
!      Set up recovery parameters in <filename>postgresql.conf</> (see
!      <xref linkend="runtime-config-wal-archive-recovery"> and
!      <xref linkend="runtime-config-wal-recovery-target">).
!     </para>
!    </listitem>
!    <listitem>
!     <para>
!      Create a recovery status file <filename>recovery.ready</>
!      in the cluster data directory. You might
       also want to temporarily modify <filename>pg_hba.conf</> to prevent
       ordinary users from connecting until you are sure the recovery was successful.
      </para>
***************
*** 1008,1014 **** SELECT pg_stop_backup();
       recovery be terminated because of an external error, the server can
       simply be restarted and it will continue recovery.  Upon completion
       of the recovery process, the server will rename
!      <filename>recovery.conf</> to <filename>recovery.done</> (to prevent
       accidentally re-entering recovery mode later) and then
       commence normal database operations.
      </para>
--- 1015,1021 ----
       recovery be terminated because of an external error, the server can
       simply be restarted and it will continue recovery.  Upon completion
       of the recovery process, the server will rename
!      <filename>recovery.ready</> to <filename>recovery.done</> (to prevent
       accidentally re-entering recovery mode later) and then
       commence normal database operations.
      </para>
***************
*** 1024,1035 **** SELECT pg_stop_backup();
     </para>
  
     <para>
!     The key part of all this is to set up a recovery configuration file that
!     describes how you want to recover and how far the recovery should
!     run.  You can use <filename>recovery.conf.sample</> (normally
!     located in the installation's <filename>share/</> directory) as a
!     prototype.  The one thing that you absolutely must specify in
!     <filename>recovery.conf</> is the <varname>restore_command</>,
      which tells <productname>PostgreSQL</> how to retrieve archived
      WAL file segments.  Like the <varname>archive_command</>, this is
      a shell command string.  It can contain <literal>%f</>, which is
--- 1031,1041 ----
     </para>
  
     <para>
!     The key part of all this is to set up recovery parameters that
!     specify how you want to recover and how far the recovery should
!     run. The one thing that you absolutely must specify in
!     <filename>postgresql.conf</> to recover from the backup is
!     the <varname>restore_command</>,
      which tells <productname>PostgreSQL</> how to retrieve archived
      WAL file segments.  Like the <varname>archive_command</>, this is
      a shell command string.  It can contain <literal>%f</>, which is
***************
*** 1085,1091 **** restore_command = 'cp /mnt/server/archivedir/%f %p'
     <para>
      If you want to recover to some previous point in time (say, right before
      the junior DBA dropped your main transaction table), just specify the
!     required stopping point in <filename>recovery.conf</>.  You can specify
      the stop point, known as the <quote>recovery target</>, either by
      date/time, named restore point or by completion of a specific transaction
      ID.  As of this writing only the date/time and named restore point options
--- 1091,1097 ----
     <para>
      If you want to recover to some previous point in time (say, right before
      the junior DBA dropped your main transaction table), just specify the
!     required stopping point in <filename>postgresql.conf</>.  You can specify
      the stop point, known as the <quote>recovery target</>, either by
      date/time, named restore point or by completion of a specific transaction
      ID.  As of this writing only the date/time and named restore point options
***************
*** 1182,1189 **** restore_command = 'cp /mnt/server/archivedir/%f %p'
      The default behavior of recovery is to recover along the same timeline
      that was current when the base backup was taken.  If you wish to recover
      into some child timeline (that is, you want to return to some state that
!     was itself generated after a recovery attempt), you need to specify the
!     target timeline ID in <filename>recovery.conf</>.  You cannot recover into
      timelines that branched off earlier than the base backup.
     </para>
    </sect2>
--- 1188,1196 ----
      The default behavior of recovery is to recover along the same timeline
      that was current when the base backup was taken.  If you wish to recover
      into some child timeline (that is, you want to return to some state that
!     was itself generated after a recovery attempt), you need to set
!     <xref linkend="guc-recovery-target-timeline"> to the
!     target timeline ID in <filename>postgresql.conf</>.  You cannot recover into
      timelines that branched off earlier than the base backup.
     </para>
    </sect2>
*** a/doc/src/sgml/config.sgml
--- b/doc/src/sgml/config.sgml
***************
*** 1961,1966 **** SET ENABLE_SEQSCAN TO OFF;
--- 1961,2238 ----
       </variablelist>
      </sect2>
  
+     <sect2 id="runtime-config-wal-archive-recovery">
+      <title>Archive Recovery</title>
+ 
+      <variablelist>
+       <varlistentry id="guc-restore-command" xreflabel="restore_command">
+        <term><varname>restore_command</varname> (<type>string</type>)</term>
+        <indexterm>
+         <primary><varname>restore_command</> configuration parameter</primary>
+        </indexterm>
+        <listitem>
+         <para>
+          The shell command to execute to retrieve an archived segment of
+          the WAL file series. This parameter is required for archive recovery,
+          but optional for streaming replication.
+          Any <literal>%f</> in the string is
+          replaced by the name of the file to retrieve from the archive,
+          and any <literal>%p</> is replaced by the copy destination path name
+          on the server.
+          (The path name is relative to the current working directory,
+          i.e., the cluster's data directory.)
+          Any <literal>%r</> is replaced by the name of the file containing the
+          last valid restart point. That is the earliest file that must be kept
+          to allow a restore to be restartable, so this information can be used
+          to truncate the archive to just the minimum required to support
+          restarting from the current restore. <literal>%r</> is typically only
+          used by warm-standby configurations
+          (see <xref linkend="warm-standby">).
+          Write <literal>%%</> to embed an actual <literal>%</> character.
+         </para>
+         <para>
+          It is important for the command to return a zero exit status
+          only if it succeeds.  The command <emphasis>will</> be asked for file
+          names that are not present in the archive; it must return nonzero
+          when so asked.  Examples:
+ <programlisting>
+ restore_command = 'cp /mnt/server/archivedir/%f "%p"'
+ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
+ </programlisting>
+         </para>
+         <para>
+          This parameter can only be set in the <filename>postgresql.conf</>
+          file or on the server command line. It only has effect during archive
+          recovery or in standby mode.
+         </para>
+        </listitem>
+       </varlistentry>
+ 
+       <varlistentry id="guc-archive-cleanup-command" xreflabel="archive_cleanup_command">
+        <term><varname>archive_cleanup_command</varname> (<type>string</type>)</term>
+        <indexterm>
+          <primary><varname>archive_cleanup_command</> configuration parameter</primary>
+        </indexterm>
+        <listitem>
+         <para>
+          The shell command that will be executed at every restartpoint.
+          The purpose of <varname>archive_cleanup_command</> is to
+          provide a mechanism for cleaning up old archived WAL files that
+          are no longer needed by the standby server.
+          Any <literal>%r</> is replaced by the name of the file containing the
+          last valid restart point.
+          That is the earliest file that must be <emphasis>kept</> to allow a
+          restore to be restartable, and so all files earlier than <literal>%r</>
+          may be safely removed.
+          This information can be used to truncate the archive to just the
+          minimum required to support restart from the current restore.
+          The <xref linkend="pgarchivecleanup"> module
+          is often used in <varname>archive_cleanup_command</> for
+          single-standby configurations, for example:
+ <programlisting>archive_cleanup_command = 'pg_archivecleanup /mnt/server/archivedir %r'</programlisting>
+          Note however that if multiple standby servers are restoring from the
+          same archive directory, you will need to ensure that you do not delete
+          WAL files until they are no longer needed by any of the servers.
+          <varname>archive_cleanup_command</> would typically be used in a
+          warm-standby configuration (see <xref linkend="warm-standby">).
+          Write <literal>%%</> to embed an actual <literal>%</> character in the
+          command.
+         </para>
+         <para>
+          If the command returns a non-zero exit status then a WARNING log
+          message will be written.
+         </para>
+         <para>
+          This parameter can only be set in the <filename>postgresql.conf</>
+          file or on the server command line. It only has effect during archive
+          recovery or in standby mode.
+         </para>
+        </listitem>
+       </varlistentry>
+ 
+       <varlistentry id="guc-recovery-end-command" xreflabel="recovery_end_command">
+        <term><varname>recovery_end_command</varname> (<type>string</type>)</term>
+        <indexterm>
+          <primary><varname>recovery_end_command</> configuration parameter</primary>
+        </indexterm>
+        <listitem>
+         <para>
+          The shell command that will be executed once only
+          at the end of recovery. This parameter is optional. The purpose of the
+          <varname>recovery_end_command</> is to provide a mechanism for cleanup
+          following replication or recovery.
+          Any <literal>%r</> is replaced by the name of the file containing the
+          last valid restart point, like in <varname>archive_cleanup_command</>.
+         </para>
+         <para>
+          If the command returns a non-zero exit status then a WARNING log
+          message will be written and the database will proceed to start up
+          anyway.  An exception is that if the command was terminated by a
+          signal, the database will not proceed with startup.
+         </para>
+         <para>
+          This parameter can only be set in the <filename>postgresql.conf</>
+          file or on the server command line. It only has effect during archive
+          recovery or in standby mode.
+         </para>
+        </listitem>
+       </varlistentry>
+      </variablelist>
+     </sect2>
+ 
+     <sect2 id="runtime-config-wal-recovery-target">
+      <title>Recovery Target</title>
+ 
+      <variablelist>
+       <varlistentry id="guc-recovery-target-name" xreflabel="recovery_target_name">
+        <term><varname>recovery_target_name</varname> (<type>string</type>)</term>
+        <indexterm>
+         <primary><varname>recovery_target_name</> configuration parameter</primary>
+        </indexterm>
+        <listitem>
+         <para>
+          Specifies the named restore point, created with
+          <function>pg_create_restore_point()</> to which recovery will proceed.
+          At most one of <varname>recovery_target_name</>,
+          <varname>recovery_target_time</> or
+          <varname>recovery_target_xid</> can be specified.  The default
+          value is an empty string, which will recover to the end of the WAL log.
+         </para>
+         <para>
+          This parameter can only be set in the <filename>postgresql.conf</>
+          file or on the server command line. It only has effect during archive
+          recovery or in standby mode.
+         </para>
+        </listitem>
+       </varlistentry>
+ 
+       <varlistentry id="guc-recovery-target-time" xreflabel="recovery_target_time">
+        <term><varname>recovery_target_time</varname> (<type>string</type>)</term>
+        <indexterm>
+         <primary><varname>recovery_target_time</> configuration parameter</primary>
+        </indexterm>
+        <listitem>
+         <para>
+          Specifies the time stamp up to which recovery will proceed.
+          This parameter must be specified in the date/time format
+          (see <xref linkend="datatype-datetime-input"> for details).
+          At most one of <varname>recovery_target_time</>,
+          <varname>recovery_target_name</> or
+          <varname>recovery_target_xid</> can be specified.
+          The default value is an empty string, which will recover to
+          the end of the WAL log. The precise stopping point is also
+          influenced by <varname>recovery_target_inclusive</>.
+         </para>
+         <para>
+          This parameter can only be set in the <filename>postgresql.conf</>
+          file or on the server command line. It only has effect during archive
+          recovery or in standby mode.
+         </para>
+        </listitem>
+       </varlistentry>
+ 
+       <varlistentry id="guc-recovery-target-xid" xreflabel="recovery_target_xid">
+        <term><varname>recovery_target_xid</varname> (<type>string</type>)</term>
+        <indexterm>
+         <primary><varname>recovery_target_xid</> configuration parameter</primary>
+        </indexterm>
+        <listitem>
+         <para>
+          Specifies the transaction ID up to which recovery will proceed.
+          Keep in mind that while transaction IDs are assigned sequentially
+          at transaction start, transactions can complete in a different
+          numeric order. The transactions that will be recovered are
+          those that committed before (and optionally including)
+          the specified one. At most one of <varname>recovery_target_xid</>,
+          <varname>recovery_target_name</> or
+          <varname>recovery_target_time</> can be specified.
+          The default value is an empty string, which will recover to the end of
+          the WAL log. The precise stopping point is also influenced by
+          <varname>recovery_target_inclusive</>.
+         </para>
+         <para>
+          This parameter can only be set in the <filename>postgresql.conf</>
+          file or on the server command line. It only has effect during archive
+          recovery or in standby mode.
+         </para>
+        </listitem>
+       </varlistentry>
+ 
+       <varlistentry id="guc-recovery-target-inclusive" xreflabel="recovery_target_inclusive">
+        <term><varname>recovery_target_inclusive</varname> (<type>boolean</type>)</term>
+        <indexterm>
+         <primary><varname>recovery_target_inclusive</> configuration parameter</primary>
+        </indexterm>
+        <listitem>
+         <para>
+          Specifies whether we stop just after the specified recovery target
+          (<literal>on</>), or just before the recovery target (<literal>off</>).
+          Applies to both <varname>recovery_target_time</>
+          and <varname>recovery_target_xid</>, whichever one is
+          specified for this recovery.  This indicates whether transactions
+          having exactly the target commit time or ID, respectively, will
+          be included in the recovery.  Default is <literal>on</>.
+         </para>
+         <para>
+          This parameter can only be set in the <filename>postgresql.conf</>
+          file or on the server command line. It only has effect during archive
+          recovery or in standby mode.
+         </para>
+        </listitem>
+       </varlistentry>
+ 
+       <varlistentry id="guc-recovery-target-timeline" xreflabel="recovery_target_timeline">
+        <term><varname>recovery_target_timeline</varname> (<type>string</type>)</term>
+        <indexterm>
+         <primary><varname>recovery_target_timeline</> configuration parameter</primary>
+        </indexterm>
+        <listitem>
+         <para>
+          Specifies recovering into a particular timeline.  The default value is
+          an empty string, which will recover along the same timeline that was
+          current when the base backup was taken. Setting this to
+          <literal>latest</> recovers to the latest timeline found in the archive,
+          which is useful in a standby server. Other than that you only need to
+          set this parameter in complex re-recovery situations, where you need
+          to return to a state that itself was reached after a point-in-time
+          recovery. See <xref linkend="backup-timelines"> for discussion.
+         </para>
+         <para>
+          This parameter can only be set at server start. It only has effect
+          during archive recovery or in standby mode.
+         </para>
+        </listitem>
+       </varlistentry>
+ 
+       <varlistentry id="guc-pause-at-recovery-target" xreflabel="pause_at_recovery_target">
+        <term><varname>pause_at_recovery_target</varname> (<type>boolean</type>)</term>
+        <indexterm>
+         <primary><varname>pause_at_recovery_target</> configuration parameter</primary>
+        </indexterm>
+        <listitem>
+         <para>
+          Specifies whether recovery should pause when the recovery target
+          is reached. The default is <literal>on</>.
+          This is intended to allow queries to be executed against the
+          database to check if this recovery target is the most desirable
+          point for recovery. The paused state can be resumed by using
+          <function>pg_xlog_replay_resume()</> (See
+          <xref linkend="functions-recovery-control-table">), which then
+          causes recovery to end. If this recovery target is not the
+          desired stopping point, then shutdown the server, change the
+          recovery target settings to a later target and restart to
+          continue recovery.
+         </para>
+         <para>
+          This parameter can only be set in the <filename>postgresql.conf</>
+          file or on the server command line. It only has effect during archive
+          recovery or in standby mode if recovery target is set.
+         </para>
+        </listitem>
+       </varlistentry>
+      </variablelist>
+      </sect2>
+ 
     </sect1>
  
     <sect1 id="runtime-config-replication">
***************
*** 2182,2187 **** SET ENABLE_SEQSCAN TO OFF;
--- 2454,2546 ----
  
      <variablelist>
  
+      <varlistentry id="guc-standby-mode" xreflabel="standby_mode">
+       <term><varname>standby_mode</varname> (<type>boolean</type>)</term>
+       <indexterm>
+        <primary><varname>standby_mode</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies whether to start the <productname>PostgreSQL</> server as
+         a standby when recovery status file <filename>recovery.ready</> exists.
+         The default value is <literal>off</>.
+         If this parameter is <literal>on</>, the server will not
+         stop recovery when the end of archived WAL is reached,
+         but will keep trying to continue recovery by fetching new WAL segments
+         using <varname>restore_command</> and/or by connecting to
+         the primary server as specified by the <varname>primary_conninfo</>
+         setting.
+        </para>
+        <para>
+         This parameter can only be set at server start. It only has effect
+         if recovery status file <filename>recovery.ready</> exists.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry id="guc-primary-conninfo" xreflabel="primary_conninfo">
+       <term><varname>primary_conninfo</varname> (<type>string</type>)</term>
+       <indexterm>
+         <primary><varname>primary_conninfo</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies a connection string to be used for the standby server
+         to connect with the primary. This string is in the format
+         accepted by the libpq <function>PQconnectdb</function> function,
+         described in <xref linkend="libpq-connect">. If any option is
+         unspecified in this string, then the corresponding environment
+         variable (see <xref linkend="libpq-envars">) is checked. If the
+         environment variable is not set either, then defaults are used.
+         If this parameter is an empty string (the default), no attempt is
+         made to connect to the master.
+        </para>
+        <para>
+         The connection string should specify the host name (or address)
+         of the primary server, as well as the port number if it is not
+         the same as the standby server's default.
+         Also specify a user name corresponding to a role that has the
+         <literal>REPLICATION</> and <literal>LOGIN</> privileges on the
+         primary (see
+         <xref linkend="streaming-replication-authentication">).
+         A password needs to be provided too, if the primary demands password
+         authentication.  It can be provided in the
+         <varname>primary_conninfo</varname> string, or in a separate
+         <filename>~/.pgpass</> file on the standby server (use
+         <literal>replication</> as the database name).
+         Do not specify a database name in the
+         <varname>primary_conninfo</varname> string.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect in standby mode.
+        </para>
+        <para>
+         If this parameter is changed while replication is in progress,
+         the standby terminates replication, and then tries to restart
+         replication with new setting.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry id="guc-trigger-file" xreflabel="trigger_file">
+       <term><varname>trigger_file</varname> (<type>string</type>)</term>
+       <indexterm>
+         <primary><varname>trigger_file</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies a trigger file whose presence ends recovery in the
+         standby.  Even if this value is not set, you can still promote
+         the standby using <command>pg_ctl promote</>.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect in standby mode.
+        </para>
+       </listitem>
+     </varlistentry>
+ 
       <varlistentry id="guc-hot-standby" xreflabel="hot_standby">
        <term><varname>hot_standby</varname> (<type>boolean</type>)</term>
        <indexterm>
*** a/doc/src/sgml/filelist.sgml
--- b/doc/src/sgml/filelist.sgml
***************
*** 42,48 ****
  <!ENTITY manage-ag     SYSTEM "manage-ag.sgml">
  <!ENTITY monitoring    SYSTEM "monitoring.sgml">
  <!ENTITY regress       SYSTEM "regress.sgml">
- <!ENTITY recovery-config SYSTEM "recovery-config.sgml">
  <!ENTITY runtime       SYSTEM "runtime.sgml">
  <!ENTITY config        SYSTEM "config.sgml">
  <!ENTITY user-manag    SYSTEM "user-manag.sgml">
--- 42,47 ----
*** a/doc/src/sgml/func.sgml
--- b/doc/src/sgml/func.sgml
***************
*** 14134,14140 **** postgres=# select pg_start_backup('label_goes_here');
      <function>pg_create_restore_point</> creates a named transaction log
      record that can be used as recovery target, and returns the corresponding
      transaction log location.  The given name can then be used with
!     <xref linkend="recovery-target-name"> to specify the point up to which
      recovery will proceed.  Avoid creating multiple restore points with the
      same name, since recovery will stop at the first one whose name matches
      the recovery target.
--- 14134,14140 ----
      <function>pg_create_restore_point</> creates a named transaction log
      record that can be used as recovery target, and returns the corresponding
      transaction log location.  The given name can then be used with
!     <xref linkend="guc-recovery-target-name"> to specify the point up to which
      recovery will proceed.  Avoid creating multiple restore points with the
      same name, since recovery will stop at the first one whose name matches
      the recovery target.
*** a/doc/src/sgml/high-availability.sgml
--- b/doc/src/sgml/high-availability.sgml
***************
*** 591,597 **** protocol to make nodes agree on a serializable transactional order.
     <para>
      In standby mode, the server continuously applies WAL received from the
      master server. The standby server can read WAL from a WAL archive
!     (see <xref linkend="restore-command">) or directly from the master
      over a TCP connection (streaming replication). The standby server will
      also attempt to restore any WAL found in the standby cluster's
      <filename>pg_xlog</> directory. That typically happens after a server
--- 591,597 ----
     <para>
      In standby mode, the server continuously applies WAL received from the
      master server. The standby server can read WAL from a WAL archive
!     (see <xref linkend="guc-restore-command">) or directly from the master
      over a TCP connection (streaming replication). The standby server will
      also attempt to restore any WAL found in the standby cluster's
      <filename>pg_xlog</> directory. That typically happens after a server
***************
*** 658,665 **** protocol to make nodes agree on a serializable transactional order.
     <para>
      To set up the standby server, restore the base backup taken from primary
      server (see <xref linkend="backup-pitr-recovery">). Create a recovery
!     command file <filename>recovery.conf</> in the standby's cluster data
!     directory, and turn on <varname>standby_mode</>. Set
      <varname>restore_command</> to a simple command to copy files from
      the WAL archive. If you plan to have multiple standby servers for high
      availability purposes, set <varname>recovery_target_timeline</> to
--- 658,665 ----
     <para>
      To set up the standby server, restore the base backup taken from primary
      server (see <xref linkend="backup-pitr-recovery">). Create a recovery
!     status file <filename>recovery.ready</> in the standby's cluster data
!     directory. Turn on <varname>standby_mode</> and set
      <varname>restore_command</> to a simple command to copy files from
      the WAL archive. If you plan to have multiple standby servers for high
      availability purposes, set <varname>recovery_target_timeline</> to
***************
*** 695,701 **** protocol to make nodes agree on a serializable transactional order.
  
     <para>
      If you're using a WAL archive, its size can be minimized using the <xref
!     linkend="archive-cleanup-command"> parameter to remove files that are no
      longer required by the standby server.
      The <application>pg_archivecleanup</> utility is designed specifically to
      be used with <varname>archive_cleanup_command</> in typical single-standby
--- 695,701 ----
  
     <para>
      If you're using a WAL archive, its size can be minimized using the <xref
!     linkend="guc-archive-cleanup-command"> parameter to remove files that are no
      longer required by the standby server.
      The <application>pg_archivecleanup</> utility is designed specifically to
      be used with <varname>archive_cleanup_command</> in typical single-standby
***************
*** 706,712 **** protocol to make nodes agree on a serializable transactional order.
     </para>
  
     <para>
!     A simple example of a <filename>recovery.conf</> is:
  <programlisting>
  standby_mode = 'on'
  primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
--- 706,712 ----
     </para>
  
     <para>
!     A simple example of standby settings is:
  <programlisting>
  standby_mode = 'on'
  primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
***************
*** 762,769 **** archive_cleanup_command = 'pg_archivecleanup /path/to/archive %r'
      To use streaming replication, set up a file-based log-shipping standby
      server as described in <xref linkend="warm-standby">. The step that
      turns a file-based log-shipping standby into streaming replication
!     standby is setting <varname>primary_conninfo</> setting in the
!     <filename>recovery.conf</> file to point to the primary server. Set
      <xref linkend="guc-listen-addresses"> and authentication options
      (see <filename>pg_hba.conf</>) on the primary so that the standby server
      can connect to the <literal>replication</> pseudo-database on the primary
--- 762,769 ----
      To use streaming replication, set up a file-based log-shipping standby
      server as described in <xref linkend="warm-standby">. The step that
      turns a file-based log-shipping standby into streaming replication
!     standby is setting <varname>primary_conninfo</> to
!     point to the primary server. Set
      <xref linkend="guc-listen-addresses"> and authentication options
      (see <filename>pg_hba.conf</>) on the primary so that the standby server
      can connect to the <literal>replication</> pseudo-database on the primary
***************
*** 832,846 **** host    replication     foo             192.168.1.100/32        md5
      </para>
      <para>
       The host name and port number of the primary, connection user name,
!      and password are specified in the <filename>recovery.conf</> file.
       The password can also be set in the <filename>~/.pgpass</> file on the
       standby (specify <literal>replication</> in the <replaceable>database</>
       field).
       For example, if the primary is running on host IP <literal>192.168.1.50</>,
       port <literal>5432</literal>, the account name for replication is
       <literal>foo</>, and the password is <literal>foopass</>, the administrator
!      can add the following line to the <filename>recovery.conf</> file on the
!      standby:
  
  <programlisting>
  # The standby connects to the primary that is running on host 192.168.1.50
--- 832,845 ----
      </para>
      <para>
       The host name and port number of the primary, connection user name,
!      and password are specified in <varname>primary_conninfo</>.
       The password can also be set in the <filename>~/.pgpass</> file on the
       standby (specify <literal>replication</> in the <replaceable>database</>
       field).
       For example, if the primary is running on host IP <literal>192.168.1.50</>,
       port <literal>5432</literal>, the account name for replication is
       <literal>foo</>, and the password is <literal>foopass</>, the administrator
!      can set <varname>primary_conninfo</> on the standby like this:
  
  <programlisting>
  # The standby connects to the primary that is running on host 192.168.1.50
***************
*** 1204,1211 **** primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
     <para>
      To trigger failover of a log-shipping standby server,
      run <command>pg_ctl promote</> or create a trigger
!     file with the file name and path specified by the <varname>trigger_file</>
!     setting in <filename>recovery.conf</>. If you're planning to use
      <command>pg_ctl promote</> to fail over, <varname>trigger_file</> is
      not required. If you're setting up the reporting servers that are
      only used to offload read-only queries from the primary, not for high
--- 1203,1210 ----
     <para>
      To trigger failover of a log-shipping standby server,
      run <command>pg_ctl promote</> or create a trigger
!     file with the file name and path specified by the <varname>trigger_file</>.
!     If you're planning to use
      <command>pg_ctl promote</> to fail over, <varname>trigger_file</> is
      not required. If you're setting up the reporting servers that are
      only used to offload read-only queries from the primary, not for high
***************
*** 1250,1257 **** primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
      The magic that makes the two loosely coupled servers work together is
      simply a <varname>restore_command</> used on the standby that,
      when asked for the next WAL file, waits for it to become available from
!     the primary. The <varname>restore_command</> is specified in the
!     <filename>recovery.conf</> file on the standby server. Normal recovery
      processing would request a file from the WAL archive, reporting failure
      if the file was unavailable.  For standby processing it is normal for
      the next WAL file to be unavailable, so the standby must wait for
--- 1249,1255 ----
      The magic that makes the two loosely coupled servers work together is
      simply a <varname>restore_command</> used on the standby that,
      when asked for the next WAL file, waits for it to become available from
!     the primary. Normal recovery
      processing would request a file from the WAL archive, reporting failure
      if the file was unavailable.  For standby processing it is normal for
      the next WAL file to be unavailable, so the standby must wait for
***************
*** 1338,1345 **** if (!triggered)
       </listitem>
       <listitem>
        <para>
         Begin recovery on the standby server from the local WAL
!        archive, using a <filename>recovery.conf</> that specifies a
         <varname>restore_command</> that waits as described
         previously (see <xref linkend="backup-pitr-recovery">).
        </para>
--- 1336,1349 ----
       </listitem>
       <listitem>
        <para>
+        Create a recovery status file <filename>recovery.ready</>
+        in the standby's cluster data directory.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
         Begin recovery on the standby server from the local WAL
!        archive, specifying a
         <varname>restore_command</> that waits as described
         previously (see <xref linkend="backup-pitr-recovery">).
        </para>
***************
*** 1830,1838 **** if (!triggered)
     <title>Administrator's Overview</title>
  
     <para>
!     If <varname>hot_standby</> is turned <literal>on</> in
!     <filename>postgresql.conf</> and there is a <filename>recovery.conf</>
!     file present, the server will run in Hot Standby mode.
      However, it may take some time for Hot Standby connections to be allowed,
      because the server will not accept connections until it has completed
      sufficient recovery to provide a consistent state against which queries
--- 1834,1842 ----
     <title>Administrator's Overview</title>
  
     <para>
!     If <varname>hot_standby</> is turned <literal>on</>
!     and there is a recovery status file
!     <filename>recovery.ready</> present, the server will run in Hot Standby mode.
      However, it may take some time for Hot Standby connections to be allowed,
      because the server will not accept connections until it has completed
      sufficient recovery to provide a consistent state against which queries
*** a/doc/src/sgml/pgarchivecleanup.sgml
--- b/doc/src/sgml/pgarchivecleanup.sgml
***************
*** 37,44 ****
  
    <para>
     To configure a standby
!    server to use <application>pg_archivecleanup</>, put this into its
!    <filename>recovery.conf</filename> configuration file:
  <programlisting>
  archive_cleanup_command = 'pg_archivecleanup <replaceable>archivelocation</> %r'
  </programlisting>
--- 37,44 ----
  
    <para>
     To configure a standby
!    server to use <application>pg_archivecleanup</>, specify
!    <xref linkend="guc-archive-cleanup-command"> like this:
  <programlisting>
  archive_cleanup_command = 'pg_archivecleanup <replaceable>archivelocation</> %r'
  </programlisting>
***************
*** 46,52 **** archive_cleanup_command = 'pg_archivecleanup <replaceable>archivelocation</> %r'
     files should be removed.
    </para>
    <para>
!    When used within <xref linkend="archive-cleanup-command">, all WAL files
     logically preceding the value of the <literal>%r</> argument will be removed
     from <replaceable>archivelocation</>. This minimizes the number of files
     that need to be retained, while preserving crash-restart capability.  Use of
--- 46,52 ----
     files should be removed.
    </para>
    <para>
!    When used within <varname>archive_cleanup_command</>, all WAL files
     logically preceding the value of the <literal>%r</> argument will be removed
     from <replaceable>archivelocation</>. This minimizes the number of files
     that need to be retained, while preserving crash-restart capability.  Use of
*** a/doc/src/sgml/pgstandby.sgml
--- b/doc/src/sgml/pgstandby.sgml
***************
*** 48,55 ****
  
    <para>
     To configure a standby
!    server to use <application>pg_standby</>, put this into its
!    <filename>recovery.conf</filename> configuration file:
  <programlisting>
  restore_command = 'pg_standby <replaceable>archiveDir</> %f %p %r'
  </programlisting>
--- 48,55 ----
  
    <para>
     To configure a standby
!    server to use <application>pg_standby</>, specify
!    <xref linkend="guc-restore-command"> like this:
  <programlisting>
  restore_command = 'pg_standby <replaceable>archiveDir</> %f %p %r'
  </programlisting>
*** a/doc/src/sgml/postgres.sgml
--- b/doc/src/sgml/postgres.sgml
***************
*** 155,161 ****
    &maintenance;
    &backup;
    &high-availability;
-   &recovery-config;
    &monitoring;
    &diskusage;
    &wal;
--- 155,160 ----
*** a/doc/src/sgml/recovery-config.sgml
--- /dev/null
***************
*** 1,363 ****
- <!-- doc/src/sgml/recovery-config.sgml -->
- 
- <chapter id="recovery-config">
-   <title>Recovery Configuration</title>
- 
-   <indexterm>
-    <primary>configuration</primary>
-    <secondary>of recovery</secondary>
-    <tertiary>of a standby server</tertiary>
-   </indexterm>
- 
-    <para>
-     This chapter describes the settings available in the
-     <filename>recovery.conf</><indexterm><primary>recovery.conf</></>
-     file. They apply only for the duration of the
-     recovery.  They must be reset for any subsequent recovery you wish to
-     perform.  They cannot be changed once recovery has begun.
-    </para>
- 
-    <para>
-      Settings in <filename>recovery.conf</> are specified in the format
-      <literal>name = 'value'</>. One parameter is specified per line.
-      Hash marks (<literal>#</literal>) designate the rest of the
-      line as a comment.  To embed a single quote in a parameter
-      value, write two quotes (<literal>''</>).
-    </para>
- 
-    <para>
-     A sample file, <filename>share/recovery.conf.sample</>,
-     is provided in the installation's <filename>share/</> directory.
-    </para>
- 
-   <sect1 id="archive-recovery-settings">
- 
-     <title>Archive Recovery Settings</title>
-      <variablelist>
- 
-      <varlistentry id="restore-command" xreflabel="restore_command">
-       <term><varname>restore_command</varname> (<type>string</type>)</term>
-       <indexterm>
-         <primary><varname>restore_command</> recovery parameter</primary>
-       </indexterm>
-       <listitem>
-        <para>
-         The shell command to execute to retrieve an archived segment of
-         the WAL file series. This parameter is required for archive recovery,
-         but optional for streaming replication.
-         Any <literal>%f</> in the string is
-         replaced by the name of the file to retrieve from the archive,
-         and any <literal>%p</> is replaced by the copy destination path name
-         on the server.
-         (The path name is relative to the current working directory,
-         i.e., the cluster's data directory.)
-         Any <literal>%r</> is replaced by the name of the file containing the
-         last valid restart point. That is the earliest file that must be kept
-         to allow a restore to be restartable, so this information can be used
-         to truncate the archive to just the minimum required to support
-         restarting from the current restore. <literal>%r</> is typically only
-         used by warm-standby configurations
-         (see <xref linkend="warm-standby">).
-         Write <literal>%%</> to embed an actual <literal>%</> character.
-        </para>
- 
-        <para>
-         It is important for the command to return a zero exit status
-         only if it succeeds.  The command <emphasis>will</> be asked for file
-         names that are not present in the archive; it must return nonzero
-         when so asked.  Examples:
- <programlisting>
- restore_command = 'cp /mnt/server/archivedir/%f "%p"'
- restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
- </programlisting>
-        </para>
-       </listitem>
-      </varlistentry>
- 
-      <varlistentry id="archive-cleanup-command" xreflabel="archive_cleanup_command">
-       <term><varname>archive_cleanup_command</varname> (<type>string</type>)</term>
-       <indexterm>
-         <primary><varname>archive_cleanup_command</> recovery parameter</primary>
-       </indexterm>
-       <listitem>
-        <para>
-         This optional parameter specifies a shell command that will be executed
-         at every restartpoint.  The purpose of
-         <varname>archive_cleanup_command</> is to provide a mechanism for
-         cleaning up old archived WAL files that are no longer needed by the
-         standby server.
-         Any <literal>%r</> is replaced by the name of the file containing the
-         last valid restart point.
-         That is the earliest file that must be <emphasis>kept</> to allow a
-         restore to be restartable, and so all files earlier than <literal>%r</>
-         may be safely removed.
-         This information can be used to truncate the archive to just the
-         minimum required to support restart from the current restore.
-         The <xref linkend="pgarchivecleanup"> module
-         is often used in <varname>archive_cleanup_command</> for
-         single-standby configurations, for example:
- <programlisting>archive_cleanup_command = 'pg_archivecleanup /mnt/server/archivedir %r'</programlisting>
-         Note however that if multiple standby servers are restoring from the
-         same archive directory, you will need to ensure that you do not delete
-         WAL files until they are no longer needed by any of the servers.
-         <varname>archive_cleanup_command</> would typically be used in a
-         warm-standby configuration (see <xref linkend="warm-standby">).
-         Write <literal>%%</> to embed an actual <literal>%</> character in the
-         command.
-        </para>
-        <para>
-         If the command returns a non-zero exit status then a WARNING log
-         message will be written.
-        </para>
-       </listitem>
-      </varlistentry>
- 
-      <varlistentry id="recovery-end-command" xreflabel="recovery_end_command">
-       <term><varname>recovery_end_command</varname> (<type>string</type>)</term>
-       <indexterm>
-         <primary><varname>recovery_end_command</> recovery parameter</primary>
-       </indexterm>
-       <listitem>
-        <para>
-         This parameter specifies a shell command that will be executed once only
-         at the end of recovery. This parameter is optional. The purpose of the
-         <varname>recovery_end_command</> is to provide a mechanism for cleanup
-         following replication or recovery.
-         Any <literal>%r</> is replaced by the name of the file containing the
-         last valid restart point, like in <xref linkend="archive-cleanup-command">.
-        </para>
-        <para>
-         If the command returns a non-zero exit status then a WARNING log
-         message will be written and the database will proceed to start up
-         anyway.  An exception is that if the command was terminated by a
-         signal, the database will not proceed with startup.
-        </para>
-       </listitem>
-      </varlistentry>
- 
-     </variablelist>
- 
-   </sect1>
- 
-   <sect1 id="recovery-target-settings">
- 
-     <title>Recovery Target Settings</title>
-      <variablelist>
- 
-      <varlistentry id="recovery-target-name" xreflabel="recovery_target_name">
-       <term><varname>recovery_target_name</varname>
-            (<type>string</type>)
-       </term>
-       <indexterm>
-         <primary><varname>recovery_target_name</> recovery parameter</primary>
-       </indexterm>
-       <listitem>
-        <para>
-         This parameter specifies the named restore point, created with
-         <function>pg_create_restore_point()</> to which recovery will proceed.
-         At most one of <varname>recovery_target_name</>,
-         <xref linkend="recovery-target-time"> or
-         <xref linkend="recovery-target-xid"> can be specified.  The default is to
-         recover to the end of the WAL log.
-        </para>
-       </listitem>
-      </varlistentry>
- 
-      <varlistentry id="recovery-target-time" xreflabel="recovery_target_time">
-       <term><varname>recovery_target_time</varname>
-            (<type>timestamp</type>)
-       </term>
-       <indexterm>
-         <primary><varname>recovery_target_time</> recovery parameter</primary>
-       </indexterm>
-       <listitem>
-        <para>
-         This parameter specifies the time stamp up to which recovery
-         will proceed.
-         At most one of <varname>recovery_target_time</>,
-         <xref linkend="recovery-target-name"> or
-         <xref linkend="recovery-target-xid"> can be specified.
-         The default is to recover to the end of the WAL log.
-         The precise stopping point is also influenced by
-         <xref linkend="recovery-target-inclusive">.
-        </para>
-       </listitem>
-      </varlistentry>
- 
-      <varlistentry id="recovery-target-xid" xreflabel="recovery_target_xid">
-       <term><varname>recovery_target_xid</varname> (<type>string</type>)</term>
-       <indexterm>
-         <primary><varname>recovery_target_xid</> recovery parameter</primary>
-       </indexterm>
-       <listitem>
-        <para>
-         This parameter specifies the transaction ID up to which recovery
-         will proceed. Keep in mind
-         that while transaction IDs are assigned sequentially at transaction
-         start, transactions can complete in a different numeric order.
-         The transactions that will be recovered are those that committed
-         before (and optionally including) the specified one.
-         At most one of <varname>recovery_target_xid</>,
-         <xref linkend="recovery-target-name"> or
-         <xref linkend="recovery-target-time"> can be specified.
-         The default is to recover to the end of the WAL log.
-         The precise stopping point is also influenced by
-         <xref linkend="recovery-target-inclusive">.
-        </para>
-       </listitem>
-      </varlistentry>
- 
-      <varlistentry id="recovery-target-inclusive"
-                    xreflabel="recovery_target_inclusive">
-       <term><varname>recovery_target_inclusive</varname>
-         (<type>boolean</type>)
-       </term>
-       <indexterm>
-         <primary><varname>recovery_target_inclusive</> recovery parameter</primary>
-       </indexterm>
-       <listitem>
-        <para>
-         Specifies whether we stop just after the specified recovery target
-         (<literal>true</literal>), or just before the recovery target
-         (<literal>false</literal>).
-         Applies to both <xref linkend="recovery-target-time">
-         and <xref linkend="recovery-target-xid">, whichever one is
-         specified for this recovery.  This indicates whether transactions
-         having exactly the target commit time or ID, respectively, will
-         be included in the recovery.  Default is <literal>true</>.
-        </para>
-       </listitem>
-      </varlistentry>
- 
-      <varlistentry id="recovery-target-timeline"
-                    xreflabel="recovery_target_timeline">
-       <term><varname>recovery_target_timeline</varname>
-         (<type>string</type>)
-       </term>
-       <indexterm>
-         <primary><varname>recovery_target_timeline</> recovery parameter</primary>
-       </indexterm>
-       <listitem>
-        <para>
-         Specifies recovering into a particular timeline.  The default is
-         to recover along the same timeline that was current when the
-         base backup was taken. Setting this to <literal>latest</> recovers
-         to the latest timeline found in the archive, which is useful in
-         a standby server. Other than that you only need to set this parameter
-         in complex re-recovery situations, where you need to return to
-         a state that itself was reached after a point-in-time recovery.
-         See <xref linkend="backup-timelines"> for discussion.
-        </para>
-       </listitem>
-      </varlistentry>
- 
-      <varlistentry id="pause-at-recovery-target"
-                    xreflabel="pause_at_recovery_target">
-       <term><varname>pause_at_recovery_target</varname>
-         (<type>boolean</type>)
-       </term>
-       <indexterm>
-         <primary><varname>pause_at_recovery_target</> recovery parameter</primary>
-       </indexterm>
-       <listitem>
-        <para>
-         Specifies whether recovery should pause when the recovery target
-         is reached. The default is true.
-         This is intended to allow queries to be executed against the
-         database to check if this recovery target is the most desirable
-         point for recovery. The paused state can be resumed by using
-         <function>pg_xlog_replay_resume()</> (See
-         <xref linkend="functions-recovery-control-table">), which then
-         causes recovery to end. If this recovery target is not the
-         desired stopping point, then shutdown the server, change the
-         recovery target settings to a later target and restart to
-         continue recovery.
-        </para>
-        <para>
-         This setting has no effect if <xref linkend="guc-hot-standby"> is not
-         enabled, or if no recovery target is set.
-        </para>
-       </listitem>
-      </varlistentry>
- 
-      </variablelist>
-    </sect1>
- 
-   <sect1 id="standby-settings">
- 
-     <title>Standby Server Settings</title>
-      <variablelist>
- 
-        <varlistentry id="standby-mode" xreflabel="standby_mode">
-         <term><varname>standby_mode</varname> (<type>boolean</type>)</term>
-         <indexterm>
-           <primary><varname>standby_mode</> recovery parameter</primary>
-         </indexterm>
-         <listitem>
-          <para>
-           Specifies whether to start the <productname>PostgreSQL</> server as
-           a standby. If this parameter is <literal>on</>, the server will
-           not stop recovery when the end of archived WAL is reached, but
-           will keep trying to continue recovery by fetching new WAL segments
-           using <varname>restore_command</>
-           and/or by connecting to the primary server as specified by the
-           <varname>primary_conninfo</> setting.
-          </para>
-         </listitem>
-        </varlistentry>
-        <varlistentry id="primary-conninfo" xreflabel="primary_conninfo">
-         <term><varname>primary_conninfo</varname> (<type>string</type>)</term>
-         <indexterm>
-           <primary><varname>primary_conninfo</> recovery parameter</primary>
-         </indexterm>
-         <listitem>
-          <para>
-           Specifies a connection string to be used for the standby server
-           to connect with the primary. This string is in the format
-           accepted by the libpq <function>PQconnectdb</function> function,
-           described in <xref linkend="libpq-connect">. If any option is
-           unspecified in this string, then the corresponding environment
-           variable (see <xref linkend="libpq-envars">) is checked. If the
-           environment variable is not set either, then
-           defaults are used.
-          </para>
-          <para>
-           The connection string should specify the host name (or address)
-           of the primary server, as well as the port number if it is not
-           the same as the standby server's default.
-           Also specify a user name corresponding to a role that has the
-           <literal>REPLICATION</> and <literal>LOGIN</> privileges on the
-           primary (see
-           <xref linkend="streaming-replication-authentication">).
-           A password needs to be provided too, if the primary demands password
-           authentication.  It can be provided in the
-           <varname>primary_conninfo</varname> string, or in a separate
-           <filename>~/.pgpass</> file on the standby server (use
-           <literal>replication</> as the database name).
-           Do not specify a database name in the
-           <varname>primary_conninfo</varname> string.
-          </para>
-          <para>
-           This setting has no effect if <varname>standby_mode</> is <literal>off</>.
-          </para>
-         </listitem>
-        </varlistentry>
-        <varlistentry id="trigger-file" xreflabel="trigger_file">
-         <term><varname>trigger_file</varname> (<type>string</type>)</term>
-         <indexterm>
-           <primary><varname>trigger_file</> recovery parameter</primary>
-         </indexterm>
-         <listitem>
-          <para>
-           Specifies a trigger file whose presence ends recovery in the
-           standby.  Even if this value is not set, you can still promote
-           the standby using <command>pg_ctl promote</>.
-           This setting has no effect if <varname>standby_mode</> is <literal>off</>.
-          </para>
-         </listitem>
-        </varlistentry>
- 
-      </variablelist>
-    </sect1>
- 
- </chapter>
--- 0 ----
*** a/doc/src/sgml/release-9.1.sgml
--- b/doc/src/sgml/release-9.1.sgml
***************
*** 1002,1008 ****
        <listitem>
         <para>
          Add <filename>recovery.conf</> setting <link
!         linkend="pause-at-recovery-target"><varname>pause_at_recovery_target</></link>
          to pause recovery at target (Simon Riggs)
         </para>
  
--- 1002,1008 ----
        <listitem>
         <para>
          Add <filename>recovery.conf</> setting <link
!         linkend="guc-pause-at-recovery-target"><varname>pause_at_recovery_target</></link>
          to pause recovery at target (Simon Riggs)
         </para>
  
***************
*** 1022,1028 ****
         <para>
          These named restore points can be specified as recovery
          targets using the new <filename>recovery.conf</> setting
!         <link linkend="recovery-target-name"><varname>recovery_target_name</></link>.
         </para>
        </listitem>
  
--- 1022,1028 ----
         <para>
          These named restore points can be specified as recovery
          targets using the new <filename>recovery.conf</> setting
!         <link linkend="guc-recovery-target-name"><varname>recovery_target_name</></link>.
         </para>
        </listitem>
  
***************
*** 1054,1061 ****
  
        <listitem>
         <para>
!         Allow <link
!         linkend="recovery-config"><filename>recovery.conf</></link>
          to use the same quoting behavior as <filename>postgresql.conf</>
          (Dimitri Fontaine)
         </para>
--- 1054,1060 ----
  
        <listitem>
         <para>
!         Allow <filename>recovery.conf</>
          to use the same quoting behavior as <filename>postgresql.conf</>
          (Dimitri Fontaine)
         </para>
*** a/doc/src/sgml/release.sgml
--- b/doc/src/sgml/release.sgml
***************
*** 5,12 **** Typical markup:
  
  &<>                             use & escapes
  PostgreSQL                      <productname>
! postgresql.conf, pg_hba.conf,
!         recovery.conf           <filename>
  [A-Z][A-Z_ ]+[A-Z_]             <command>, <literal>, <envar>
  [A-Za-z_][A-Za-z0-9_]+()        <function>
  -[-A-Za-z_]+                    <option>
--- 5,12 ----
  
  &<>                             use & escapes
  PostgreSQL                      <productname>
! postgresql.conf, pg_hba.conf
!         recovery.ready           <filename>
  [A-Z][A-Z_ ]+[A-Z_]             <command>, <literal>, <envar>
  [A-Za-z_][A-Za-z0-9_]+()        <function>
  -[-A-Za-z_]+                    <option>
*** a/src/backend/access/transam/recovery.conf.sample
--- b/src/backend/access/transam/recovery.conf.sample
***************
*** 2,24 ****
  # PostgreSQL recovery config file
  # -------------------------------
  #
! # Edit this file to provide the parameters that PostgreSQL needs to
! # perform an archive recovery of a database, or to act as a replication
! # standby.
  #
! # If "recovery.conf" is present in the PostgreSQL data directory, it is
! # read on postmaster startup.  After successful recovery, it is renamed
! # to "recovery.done" to ensure that we do not accidentally re-enter
! # archive recovery or standby mode.
  #
! # This file consists of lines of the form:
! #
! #   name = value
! #
! # Comments are introduced with '#'.
! #
! # The complete list of option names and allowed values can be found
! # in the PostgreSQL documentation.
  #
  #---------------------------------------------------------------------------
  # ARCHIVE RECOVERY PARAMETERS
--- 2,15 ----
  # PostgreSQL recovery config file
  # -------------------------------
  #
! # PostgreSQL 9.2 or later, recovery.conf is no longer used. Instead,
! # specify all recovery parameters in postgresql.conf and create
! # recovery.ready to enter archive recovery or standby mode.
  #
! # If you must use recovery.conf, specify "include directives" in
! # postgresql.conf like this:
  #
! #   include 'recovery.conf'
  #
  #---------------------------------------------------------------------------
  # ARCHIVE RECOVERY PARAMETERS
*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
***************
*** 63,69 ****
  
  
  /* File path names (all relative to $PGDATA) */
! #define RECOVERY_COMMAND_FILE	"recovery.conf"
  #define RECOVERY_COMMAND_DONE	"recovery.done"
  #define PROMOTE_SIGNAL_FILE "promote"
  
--- 63,69 ----
  
  
  /* File path names (all relative to $PGDATA) */
! #define RECOVERY_COMMAND_READY	"recovery.ready"
  #define RECOVERY_COMMAND_DONE	"recovery.done"
  #define PROMOTE_SIGNAL_FILE "promote"
  
***************
*** 80,85 **** bool		fullPageWrites = true;
--- 80,99 ----
  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;
***************
*** 186,208 **** 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];
--- 200,207 ----
  /* 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];
***************
*** 408,419 **** 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
  	 * recovery.  Protected by info_lck.
  	 */
--- 407,412 ----
***************
*** 602,608 **** static void XLogArchiveNotifySeg(uint32 log, uint32 seg);
  static bool XLogArchiveCheckDone(const char *xlog);
  static bool XLogArchiveIsBusy(const char *xlog);
  static void XLogArchiveCleanup(const char *xlog);
! static void readRecoveryCommandFile(void);
  static void exitArchiveRecovery(TimeLineID endTLI,
  					uint32 endLogId, uint32 endLogSeg);
  static bool recoveryStopsHere(XLogRecord *record, bool *includeThis);
--- 595,601 ----
  static bool XLogArchiveCheckDone(const char *xlog);
  static bool XLogArchiveIsBusy(const char *xlog);
  static void XLogArchiveCleanup(const char *xlog);
! static void CheckRecoveryReadyFile(void);
  static void exitArchiveRecovery(TimeLineID endTLI,
  					uint32 endLogId, uint32 endLogSeg);
  static bool recoveryStopsHere(XLogRecord *record, bool *includeThis);
***************
*** 612,617 **** static void SetRecoveryPause(bool recoveryPause);
--- 605,611 ----
  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);
***************
*** 2932,2938 **** RestoreArchivedFile(char *path, const char *xlogfname,
  	uint32		restartSeg;
  
  	/* In standby mode, restore_command might not be supplied */
! 	if (recoveryRestoreCommand == NULL)
  		goto not_available;
  
  	/*
--- 2926,2932 ----
  	uint32		restartSeg;
  
  	/* In standby mode, restore_command might not be supplied */
! 	if (!restore_command[0])
  		goto not_available;
  
  	/*
***************
*** 2952,2958 **** 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
--- 2946,2952 ----
  	 * 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
***************
*** 3016,3022 **** RestoreArchivedFile(char *path, const char *xlogfname,
  	endp = xlogRestoreCmd + MAXPGPATH - 1;
  	*endp = '\0';
  
! 	for (sp = recoveryRestoreCommand; *sp; sp++)
  	{
  		if (*sp == '%')
  		{
--- 3010,3016 ----
  	endp = xlogRestoreCmd + MAXPGPATH - 1;
  	*endp = '\0';
  
! 	for (sp = restore_command; *sp; sp++)
  	{
  		if (*sp == '%')
  		{
***************
*** 3107,3113 **** 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;
--- 3101,3107 ----
  				 * 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;
***************
*** 3283,3289 **** ExecuteRecoveryCommand(char *command, char *commandName, bool failOnSignal)
  
  		ereport((signaled && failOnSignal) ? FATAL : WARNING,
  		/*------
! 		   translator: First %s represents a recovery.conf parameter name like
  		  "recovery_end_command", and the 2nd is the value of that parameter. */
  				(errmsg("%s \"%s\": return code %d", commandName,
  						command, rc)));
--- 3277,3283 ----
  
  		ereport((signaled && failOnSignal) ? FATAL : WARNING,
  		/*------
! 		   translator: First %s represents a recovery parameter name like
  		  "recovery_end_command", and the 2nd is the value of that parameter. */
  				(errmsg("%s \"%s\": return code %d", commandName,
  						command, rc)));
***************
*** 4064,4070 **** next_record_is_invalid:
  	}
  
  	/* In standby-mode, keep trying */
! 	if (StandbyMode)
  		goto retry;
  	else
  		return NULL;
--- 4058,4064 ----
  	}
  
  	/* In standby-mode, keep trying */
! 	if (standby_mode)
  		goto retry;
  	else
  		return NULL;
***************
*** 4523,4529 **** 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",
--- 4517,4523 ----
  	 * 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",
***************
*** 4531,4537 **** 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",
--- 4525,4531 ----
  				 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",
***************
*** 4539,4545 **** 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",
--- 4533,4539 ----
  				 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",
***************
*** 5268,5498 **** str_time(pg_time_t tnow)
  }
  
  /*
!  * See if there is a recovery command file (recovery.conf), and if so
!  * read in parameters for archive recovery and XLOG streaming.
!  *
!  * The file is parsed using the main configuration parser.
   */
  static void
! readRecoveryCommandFile(void)
  {
! 	FILE	   *fd;
! 	TimeLineID	rtli = 0;
! 	bool		rtliGiven = false;
! 	ConfigVariable *item,
! 			   *head = NULL,
! 			   *tail = NULL;
! 
! 	fd = AllocateFile(RECOVERY_COMMAND_FILE, "r");
! 	if (fd == NULL)
! 	{
! 		if (errno == ENOENT)
! 			return;				/* not there, so no archive recovery */
! 		ereport(FATAL,
! 				(errcode_for_file_access(),
! 				 errmsg("could not open recovery command file \"%s\": %m",
! 						RECOVERY_COMMAND_FILE)));
! 	}
! 
! 	/*
! 	 * Since we're asking ParseConfigFp() to error out at FATAL, there's no
! 	 * need to check the return value.
! 	 */
! 	ParseConfigFp(fd, RECOVERY_COMMAND_FILE, 0, FATAL, &head, &tail);
! 
! 	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
  	 * "latest" value.	We can't do this until after we've gotten the restore
  	 * 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
--- 5262,5305 ----
  }
  
  /*
!  * Check to see if there is a recovery status file (recovery.ready), and if so
!  * validate recovery parameters and determine recovery target timeline
   */
  static void
! CheckRecoveryReadyFile(void)
  {
! 	struct stat stat_buf;
  
! 	if (stat(RECOVERY_COMMAND_READY, &stat_buf) != 0)
! 		return;		/* not there, so no archive recovery */
  
  	/* 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
  	 * "latest" value.	We can't do this until after we've gotten the restore
  	 * 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
***************
*** 5502,5510 **** readRecoveryCommandFile(void)
  			recoveryTargetIsLatest = true;
  		}
  	}
- 
- 	FreeConfigVariables(head);
- 	FreeFile(fd);
  }
  
  /*
--- 5309,5314 ----
***************
*** 5580,5590 **** exitArchiveRecovery(TimeLineID endTLI, uint32 endLogId, uint32 endLogSeg)
  	 * re-enter archive recovery mode in a subsequent crash.
  	 */
  	unlink(RECOVERY_COMMAND_DONE);
! 	if (rename(RECOVERY_COMMAND_FILE, RECOVERY_COMMAND_DONE) != 0)
  		ereport(FATAL,
  				(errcode_for_file_access(),
  				 errmsg("could not rename file \"%s\" to \"%s\": %m",
! 						RECOVERY_COMMAND_FILE, RECOVERY_COMMAND_DONE)));
  
  	ereport(LOG,
  			(errmsg("archive recovery complete")));
--- 5384,5394 ----
  	 * re-enter archive recovery mode in a subsequent crash.
  	 */
  	unlink(RECOVERY_COMMAND_DONE);
! 	if (rename(RECOVERY_COMMAND_READY, RECOVERY_COMMAND_DONE) != 0)
  		ereport(FATAL,
  				(errcode_for_file_access(),
  				 errmsg("could not rename file \"%s\" to \"%s\": %m",
! 						RECOVERY_COMMAND_READY, RECOVERY_COMMAND_DONE)));
  
  	ereport(LOG,
  			(errmsg("archive recovery complete")));
***************
*** 5647,5653 **** 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
--- 5451,5457 ----
  		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
***************
*** 5658,5664 **** recoveryStopsHere(XLogRecord *record, bool *includeThis)
  		return false;
  	}
  
! 	if (recoveryTarget == RECOVERY_TARGET_XID)
  	{
  		/*
  		 * There can be only one transaction end record with this exact
--- 5462,5468 ----
  		return false;
  	}
  
! 	if (recovery_target == RECOVERY_TARGET_XID)
  	{
  		/*
  		 * There can be only one transaction end record with this exact
***************
*** 5669,5688 **** 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;
--- 5473,5492 ----
  		 * 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;
***************
*** 5694,5709 **** 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;
--- 5498,5514 ----
  		 * 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;
***************
*** 6004,6009 **** CheckRequiredParameterValues(void)
--- 5809,5827 ----
  }
  
  /*
+  * 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
***************
*** 6097,6106 **** StartupXLOG(void)
  	recoveryTargetTLI = ControlFile->checkPointCopy.ThisTimeLineID;
  
  	/*
! 	 * Check for recovery control file, and if so set up state for offline
  	 * recovery
  	 */
! 	readRecoveryCommandFile();
  
  	/* Now we can determine the list of expected TLIs */
  	expectedTLIs = readTimeLineHistory(recoveryTargetTLI);
--- 5915,5924 ----
  	recoveryTargetTLI = ControlFile->checkPointCopy.ThisTimeLineID;
  
  	/*
! 	 * Check for recovery status file, and if so set up state for offline
  	 * recovery
  	 */
! 	CheckRecoveryReadyFile();
  
  	/* Now we can determine the list of expected TLIs */
  	expectedTLIs = readTimeLineHistory(recoveryTargetTLI);
***************
*** 6118,6149 **** StartupXLOG(void)
  						ControlFile->checkPointCopy.ThisTimeLineID)));
  
  	/*
! 	 * Save the selected recovery target timeline ID and
! 	 * archive_cleanup_command in shared memory so that other processes can
! 	 * 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")));
--- 5936,5951 ----
  						ControlFile->checkPointCopy.ThisTimeLineID)));
  
  	/*
! 	 * Save the selected recovery target timeline ID in shared memory
! 	 * so that other processes can see it
  	 */
  	XLogCtl->RecoveryTargetTLI = recoveryTargetTLI;
  
  	if (InArchiveRecovery)
  	{
! 		if (standby_mode)
  			ereport(LOG,
  					(errmsg("entering standby mode")));
  		else
  			ereport(LOG,
  					(errmsg("starting archive recovery")));
***************
*** 6153,6159 **** 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))
--- 5955,5961 ----
  	 * 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))
***************
*** 6211,6217 **** 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
--- 6013,6019 ----
  					(errmsg("checkpoint record is at %X/%X",
  							checkPointLoc.xlogid, checkPointLoc.xrecoff)));
  		}
! 		else if (standby_mode)
  		{
  			/*
  			 * The last valid checkpoint record required for a streaming
***************
*** 6280,6286 **** StartupXLOG(void)
  
  	/*
  	 * Check whether we need to force recovery from WAL.  If it appears to
! 	 * have been a clean shutdown and we did not have a recovery.conf file,
  	 * then assume no recovery needed.
  	 */
  	if (XLByteLT(checkPoint.redo, RecPtr))
--- 6082,6088 ----
  
  	/*
  	 * Check whether we need to force recovery from WAL.  If it appears to
! 	 * have been a clean shutdown and we did not have a recovery.ready file,
  	 * then assume no recovery needed.
  	 */
  	if (XLByteLT(checkPoint.redo, RecPtr))
***************
*** 6294,6300 **** StartupXLOG(void)
  		InRecovery = true;
  	else if (InArchiveRecovery)
  	{
! 		/* force recovery due to presence of recovery.conf */
  		InRecovery = true;
  	}
  
--- 6096,6102 ----
  		InRecovery = true;
  	else if (InArchiveRecovery)
  	{
! 		/* force recovery due to presence of recovery.ready */
  		InRecovery = true;
  	}
  
***************
*** 6564,6570 **** StartupXLOG(void)
  					 * Pause only if users can connect to send a resume
  					 * message
  					 */
! 					if (recoveryPauseAtTarget && standbyState == STANDBY_SNAPSHOT_READY)
  					{
  						SetRecoveryPause(true);
  						recoveryPausesHere();
--- 6366,6372 ----
  					 * Pause only if users can connect to send a resume
  					 * message
  					 */
! 					if (pause_at_recovery_target && standbyState == STANDBY_SNAPSHOT_READY)
  					{
  						SetRecoveryPause(true);
  						recoveryPausesHere();
***************
*** 6663,6669 **** 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);
  
  	/*
--- 6465,6471 ----
  	 * 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);
  
  	/*
***************
*** 6671,6677 **** 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
--- 6473,6479 ----
  	 * 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
***************
*** 6864,6871 **** StartupXLOG(void)
  		/*
  		 * And finally, execute the recovery_end_command, if any.
  		 */
! 		if (recoveryEndCommand)
! 			ExecuteRecoveryCommand(recoveryEndCommand,
  								   "recovery_end_command",
  								   true);
  	}
--- 6666,6673 ----
  		/*
  		 * And finally, execute the recovery_end_command, if any.
  		 */
! 		if (recovery_end_command[0])
! 			ExecuteRecoveryCommand(recovery_end_command,
  								   "recovery_end_command",
  								   true);
  	}
***************
*** 8188,8195 **** CreateRestartPoint(int flags)
  	/*
  	 * Finally, execute archive_cleanup_command, if any.
  	 */
! 	if (XLogCtl->archiveCleanupCommand[0])
! 		ExecuteRecoveryCommand(XLogCtl->archiveCleanupCommand,
  							   "archive_cleanup_command",
  							   false);
  
--- 7990,7997 ----
  	/*
  	 * Finally, execute archive_cleanup_command, if any.
  	 */
! 	if (archive_cleanup_command[0])
! 		ExecuteRecoveryCommand(archive_cleanup_command,
  							   "archive_cleanup_command",
  							   false);
  
***************
*** 10020,10025 **** HandleStartupProcInterrupts(void)
--- 9822,9830 ----
  	{
  		got_SIGHUP = false;
  		ProcessConfigFile(PGC_SIGHUP);
+ 
+ 		/* Check for compulsory parameter */
+ 		CheckRestoreCommandSet();
  	}
  
  	/*
***************
*** 10144,10150 **** 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))
  			{
--- 9949,9955 ----
  		 * 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))
  			{
***************
*** 10166,10172 **** retry:
  	if (readFile < 0 ||
  		(readSource == XLOG_FROM_STREAM && !XLByteLT(*RecPtr, receivedUpto)))
  	{
! 		if (StandbyMode)
  		{
  			/*
  			 * In standby mode, wait for the requested record to become
--- 9971,9977 ----
  	if (readFile < 0 ||
  		(readSource == XLOG_FROM_STREAM && !XLByteLT(*RecPtr, receivedUpto)))
  	{
! 		if (standby_mode)
  		{
  			/*
  			 * In standby mode, wait for the requested record to become
***************
*** 10330,10340 **** retry:
  						 * backwards to start redo at RedoStartLSN, we will
  						 * have the logs streamed already.
  						 */
! 						if (PrimaryConnInfo)
  						{
  							RequestXLogStreaming(
! 									  fetching_ckpt ? RedoStartLSN : *RecPtr,
! 												 PrimaryConnInfo);
  							continue;
  						}
  					}
--- 10135,10144 ----
  						 * backwards to start redo at RedoStartLSN, we will
  						 * have the logs streamed already.
  						 */
! 						if (primary_conninfo[0])
  						{
  							RequestXLogStreaming(
! 									  fetching_ckpt ? RedoStartLSN : *RecPtr);
  							continue;
  						}
  					}
***************
*** 10477,10483 **** next_record_is_invalid:
  	readSource = 0;
  
  	/* In standby-mode, keep trying */
! 	if (StandbyMode)
  		goto retry;
  	else
  		return false;
--- 10281,10287 ----
  	readSource = 0;
  
  	/* In standby-mode, keep trying */
! 	if (standby_mode)
  		goto retry;
  	else
  		return false;
***************
*** 10549,10563 **** 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;
  	}
--- 10353,10367 ----
  		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/commands/extension.c
--- b/src/backend/commands/extension.c
***************
*** 9,15 ****
   * dependent objects can be associated with it.  An extension is created by
   * populating the pg_extension catalog from a "control" file.
   * The extension control file is parsed with the same parser we use for
!  * postgresql.conf and recovery.conf.  An extension also has an installation
   * script file, containing SQL commands to create the extension's objects.
   *
   * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
--- 9,15 ----
   * dependent objects can be associated with it.  An extension is created by
   * populating the pg_extension catalog from a "control" file.
   * The extension control file is parsed with the same parser we use for
!  * postgresql.conf.  An extension also has an installation
   * script file, containing SQL commands to create the extension's objects.
   *
   * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
*** a/src/backend/replication/walreceiver.c
--- b/src/backend/replication/walreceiver.c
***************
*** 168,174 **** DisableWalRcvImmediateExit(void)
  void
  WalReceiverMain(void)
  {
- 	char		conninfo[MAXCONNINFO];
  	XLogRecPtr	startpoint;
  
  	/* use volatile pointer to prevent code rearrangement */
--- 168,173 ----
***************
*** 216,222 **** WalReceiverMain(void)
  	walrcv->walRcvState = WALRCV_RUNNING;
  
  	/* Fetch information required to start streaming */
- 	strlcpy(conninfo, (char *) walrcv->conninfo, MAXCONNINFO);
  	startpoint = walrcv->receiveStart;
  	SpinLockRelease(&walrcv->mutex);
  
--- 215,220 ----
***************
*** 272,278 **** WalReceiverMain(void)
  
  	/* Establish the connection to the primary for XLOG streaming */
  	EnableWalRcvImmediateExit();
! 	walrcv_connect(conninfo, startpoint);
  	DisableWalRcvImmediateExit();
  
  	/* Loop until end-of-streaming or error */
--- 270,276 ----
  
  	/* Establish the connection to the primary for XLOG streaming */
  	EnableWalRcvImmediateExit();
! 	walrcv_connect(primary_conninfo, startpoint);
  	DisableWalRcvImmediateExit();
  
  	/* Loop until end-of-streaming or error */
***************
*** 302,309 **** WalReceiverMain(void)
--- 300,320 ----
  
  		if (got_SIGHUP)
  		{
+ 			char	*conninfo = pstrdup(primary_conninfo);
+ 
  			got_SIGHUP = false;
  			ProcessConfigFile(PGC_SIGHUP);
+ 
+ 			/*
+ 			 * If primary_conninfo has been changed while walreceiver is running,
+ 			 * shut down walreceiver so that new walreceiver is started and
+ 			 * it initiates replication with new primary_conninfo.
+ 			 */
+ 			if (strcmp(conninfo, primary_conninfo) != 0)
+ 				ereport(FATAL,
+ 						(errcode(ERRCODE_ADMIN_SHUTDOWN),
+ 						 errmsg("terminating walreceiver process because primary_conninfo was changed")));
+ 			pfree(conninfo);
  		}
  
  		/* Wait a while for data to arrive */
*** a/src/backend/replication/walreceiverfuncs.c
--- b/src/backend/replication/walreceiverfuncs.c
***************
*** 166,176 **** ShutdownWalRcv(void)
  /*
   * Request postmaster to start walreceiver.
   *
!  * recptr indicates the position where streaming should begin, and conninfo
!  * is a libpq connection string to use.
   */
  void
! RequestXLogStreaming(XLogRecPtr recptr, const char *conninfo)
  {
  	/* use volatile pointer to prevent code rearrangement */
  	volatile WalRcvData *walrcv = WalRcv;
--- 166,175 ----
  /*
   * Request postmaster to start walreceiver.
   *
!  * recptr indicates the position where streaming should begin.
   */
  void
! RequestXLogStreaming(XLogRecPtr recptr)
  {
  	/* use volatile pointer to prevent code rearrangement */
  	volatile WalRcvData *walrcv = WalRcv;
***************
*** 190,199 **** RequestXLogStreaming(XLogRecPtr recptr, const char *conninfo)
  	/* It better be stopped before we try to restart it */
  	Assert(walrcv->walRcvState == WALRCV_STOPPED);
  
- 	if (conninfo != NULL)
- 		strlcpy((char *) walrcv->conninfo, conninfo, MAXCONNINFO);
- 	else
- 		walrcv->conninfo[0] = '\0';
  	walrcv->walRcvState = WALRCV_STARTING;
  	walrcv->startTime = now;
  
--- 189,194 ----
*** 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"
***************
*** 206,211 **** static bool check_application_name(char **newval, void **extra, GucSource source
--- 207,220 ----
  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,
***************
*** 477,482 **** static int	wal_block_size;
--- 486,493 ----
  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;
***************
*** 556,561 **** const char *const config_group_names[] =
--- 567,576 ----
  	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 */
***************
*** 1366,1371 **** static struct config_bool ConfigureNamesBool[] =
--- 1381,1416 ----
  	},
  
  	{
+ 		{"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
***************
*** 2522,2527 **** static struct config_string ConfigureNamesString[] =
--- 2567,2662 ----
  	},
  
  	{
+ 		{"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,
***************
*** 8691,8694 **** show_log_file_mode(void)
--- 8826,8978 ----
  	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,214 ----
  #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 = ''		# timeline ID or 'latest'
+ 					# (change requires restart)
+ 
  
  #------------------------------------------------------------------------------
  # REPLICATION
***************
*** 219,224 ****
--- 236,245 ----
  
  # 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/bin/pg_ctl/pg_ctl.c
--- b/src/bin/pg_ctl/pg_ctl.c
***************
*** 883,889 **** do_stop(void)
  		/*
  		 * If backup_label exists, an online backup is running. Warn the user
  		 * that smart shutdown will wait for it to finish. However, if
! 		 * recovery.conf is also present, we're recovering from an online
  		 * backup instead of performing one.
  		 */
  		if (shutdown_mode == SMART_MODE &&
--- 883,889 ----
  		/*
  		 * If backup_label exists, an online backup is running. Warn the user
  		 * that smart shutdown will wait for it to finish. However, if
! 		 * recovery.ready is also present, we're recovering from an online
  		 * backup instead of performing one.
  		 */
  		if (shutdown_mode == SMART_MODE &&
***************
*** 971,977 **** do_restart(void)
  		/*
  		 * If backup_label exists, an online backup is running. Warn the user
  		 * that smart shutdown will wait for it to finish. However, if
! 		 * recovery.conf is also present, we're recovering from an online
  		 * backup instead of performing one.
  		 */
  		if (shutdown_mode == SMART_MODE &&
--- 971,977 ----
  		/*
  		 * If backup_label exists, an online backup is running. Warn the user
  		 * that smart shutdown will wait for it to finish. However, if
! 		 * recovery.ready is also present, we're recovering from an online
  		 * backup instead of performing one.
  		 */
  		if (shutdown_mode == SMART_MODE &&
***************
*** 1082,1088 **** do_promote(void)
  		exit(1);
  	}
  
! 	/* If recovery.conf doesn't exist, the server is not in standby mode */
  	if (stat(recovery_file, &statbuf) != 0)
  	{
  		write_stderr(_("%s: cannot promote server; "
--- 1082,1088 ----
  		exit(1);
  	}
  
! 	/* If recovery.ready doesn't exist, the server is not in standby mode */
  	if (stat(recovery_file, &statbuf) != 0)
  	{
  		write_stderr(_("%s: cannot promote server; "
***************
*** 2163,2169 **** main(int argc, char **argv)
  		snprintf(postopts_file, MAXPGPATH, "%s/postmaster.opts", pg_data);
  		snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
  		snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data);
! 		snprintf(recovery_file, MAXPGPATH, "%s/recovery.conf", pg_data);
  		snprintf(promote_file, MAXPGPATH, "%s/promote", pg_data);
  	}
  
--- 2163,2169 ----
  		snprintf(postopts_file, MAXPGPATH, "%s/postmaster.opts", pg_data);
  		snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
  		snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data);
! 		snprintf(recovery_file, MAXPGPATH, "%s/recovery.ready", pg_data);
  		snprintf(promote_file, MAXPGPATH, "%s/promote", pg_data);
  	}
  
*** 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,116 **** extern Size WalRcvShmemSize(void);
  extern void WalRcvShmemInit(void);
  extern void ShutdownWalRcv(void);
  extern bool WalRcvInProgress(void);
! extern void RequestXLogStreaming(XLogRecPtr recptr, const char *conninfo);
  extern XLogRecPtr GetWalRcvWriteRecPtr(XLogRecPtr *latestChunkStart);
  
  #endif   /* _WALRECEIVER_H */
--- 110,116 ----
  extern void WalRcvShmemInit(void);
  extern void ShutdownWalRcv(void);
  extern bool WalRcvInProgress(void);
! extern void RequestXLogStreaming(XLogRecPtr recptr);
  extern XLogRecPtr GetWalRcvWriteRecPtr(XLogRecPtr *latestChunkStart);
  
  #endif   /* _WALRECEIVER_H */
*** 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,
