Hello,

Here's an attempt to revive this patch.

It is rebased onto the latest master and also includes handling and
documentation of newly added recovery.conf parameters such as
primary_slot_name, recovery_min_apply_delay and
recovery_target='immediate'.

The following feedback had been addressed:

Andres Freund <and...@2ndquadrant.com> writes:
>> >
>> > * --write-standby-enable seems to loose quite some functionality in
>> >   comparison to --write-recovery-conf since it doesn't seem to set
>> >   primary_conninfo, standby anymore.
>> 
>> we can add code that looks for postgresql.conf in $PGDATA but if
>> postgresql.conf is not there (like the case in debian, there is not
>> much we can do about it) or we can write a file ready to be included
>> in postgresql.conf, any sugestion?
>
> People might not like me for the suggestion, but I think we should
> simply always include a 'recovery.conf' in $PGDATA
> unconditionally. That'd make this easier.
> Alternatively we could pass a filename to --write-recovery-conf.

Well, the latest version of this patch fails to start when it sees
'recovery.conf' in PGDATA:

  FATAL:  "recovery.conf" is not supported anymore as a recovery method
  DETAIL:  Refer to appropriate documentation about migration methods

I've missed all the discussion behind this decision and after reading
the ALTER SYSTEM/conf.d thread I'm even more confused so I'd like
someone more knowledgeable to speak up on the status of this.

Do we want to keep this behavior of the patch?

>> > * CheckRecoveryReadyFile() doesn't seem to be a very descriptive
>> >   function name.
>> 
>> I left it as CheckStartingAsStandby() but i still have a problem of
>> this not being completely clear. this function is useful for standby
>> or pitr.

There's not much left for this function in the current patch version, so
maybe we should just move it to StartupXLOG (it's not called from
anywhere else either way).

>> which leads me to the other problem i have: the recovery trigger file,
>> i have left it as standby.enabled but i still don't like it.
>
>> recovery.trigger (Andres objected on this name)
>> forced_recovery.trigger
>> user_forced_recovery.trigger
>
> stay_in_recovery.trigger? That'd be pretty clear for anybody involved in
> pg, but otherwise...

The docs use the term "continuous recovery".

Either way, from the code it is clear that we only stay in recovery if
standby_mode is directly turned on.  This makes the whole check for a
specially named file unnecessary, IMO: we should just check the value of
standby_mode (which is off by default).

By the way, is there any use in setting standby_mode=on and any of the
recovery_target* GUCs at the same time?

I think it can only play together if you set the target farther than the
latest point you've got in the archive locally.  So that's sort of
"Point-in-Future-Recovery".  Does that make any sense at all?

>> > * the description of archive_cleanup_command seems wrong to me.
>> 
>> why? it seems to be the same that was in recovery.conf. where did you
>> see the description you're complaining at?
>
> I dislike the description in guc.c
>
>> +            {"archive_cleanup_command", PGC_POSTMASTER, 
>> WAL_ARCHIVE_RECOVERY,
>> +                    gettext_noop("Sets the shell command that will be 
>> executed at every restartpoint."),
>> +                    NULL
>> +            },
>> +            &archive_cleanup_command,
>
> previously it was:
>
>> -# specifies an optional shell command to execute at every restartpoint.
>> -# This can be useful for cleaning up the archive of a standby server.

Expanded the GUC desc.

>> > * Why the PG_TRY/PG_CATCH in check_recovery_target_time? Besides being
>> >   really strangely formatted (multiline :? inside a function?) it
>> >   doesn't a) seem to be correct to ignore potential memory allocation
>> >   errors by just switching back into the context that just errored out,
>> >   and continue to work there b) forgo cleanup by just continuing as if
>> >   nothing happened. That's unlikely to be acceptable.
>> 
>> the code that read recovery.conf didn't has that, so i just removed it
>
> Well, that's not necessarily correct. recovery.conf was only read during
> startup, while this is read on SIGHUP.
>
[copied from the bottom, related]
>
> I don't think that's correct. Afaics it will cause the postmaster to
> crash on a SIGHUP with invalid data. I think you're unfortunately going
> to have to copy a fair bit of timestamptz_in() and even
> DateTimeParseError(), replacing the ereport()s by the guc error
> reporting.

The use of PG_TRY/CATCH does protect from FATALs in SIGHUP indeed.
Using CopyErrorData() we can also fetch the actual error message from
timestamptz_in, though I wonder we really have to make a full copy.

>> > * Why do you include xlog_internal.h in guc.c and not xlog.h?
>
>> we actually need both but including xlog_internal.h also includes xlog.h
>> i added xlog.h and if someone things is enough only putting
>> xlog_internal.h let me know
>
> What's required from xlog_internal.h?

Looks like this was addressed before me.

>> diff --git a/src/backend/access/transam/xlog.c 
>> b/src/backend/access/transam/xlog.c
>> index b53ae87..54f6a0d 100644
>> --- a/src/backend/access/transam/xlog.c
>> +++ b/src/backend/access/transam/xlog.c
>> @@ -64,11 +64,12 @@
>>  extern uint32 bootstrap_data_checksum_version;
>>  
>>  /* File path names (all relative to $PGDATA) */
>> -#define RECOVERY_COMMAND_FILE       "recovery.conf"
>> -#define RECOVERY_COMMAND_DONE       "recovery.done"
>> +#define RECOVERY_ENABLE_FILE        "standby.enabled"
>
> Imo the file and variable names should stay coherent.

Yes, once we settle on the name (and if we really need that extra
trigger file.)

>> +/* recovery.conf is not supported anymore */
>> +#define RECOVERY_COMMAND_FILE       "recovery.conf"
>
>> +bool                StandbyModeRequested = false;
>> +static TimestampTz recoveryDelayUntilTime;
>
> This imo should be lowercase now, the majority of GUC variables are.

This is not a GUC variable, though it's calculated based on a GUC
recovery_min_apply_delay.

>> +/* are we currently in standby mode? */
>> +bool StandbyMode = false;
>
> Why did you move this?

It was easy to move it back though.

>> -    if (rtliGiven)
>> +    if (strcmp(recovery_target_timeline_string, "") != 0)
>>      {
>
> Why not have the convention that NULL indicates a unset target_timeline
> like you use for other GUCs? Mixing things like this is confusing.
>
> Why is recovery_target_timeline stored as a string? Because it's a
> unsigned int? If so, you should have an assign hook setting up a)
> rtliGiven, b) properly typed variable.

Yes, I believe setting these to NULL by default makes a lot more sense.
Then one can check if there was a non-default setting by checking the
*_string variable, which is not possible with int or TimestampTz.

>> -            if (rtli)
>> +            if (recovery_target_timeline)
>>              {
>>                      /* Timeline 1 does not have a history file, all else 
>> should */
>> -                    if (rtli != 1 && !existsTimeLineHistory(rtli))
>> +                    if (recovery_target_timeline != 1 && 
>> +                            
>> !existsTimeLineHistory(recovery_target_timeline))
>>                              ereport(FATAL,
>>                                              (errmsg("recovery target 
>> timeline %u does not exist",
>> -                                                            rtli)));
>> -                    recoveryTargetTLI = rtli;
>> +                                                            
>> recovery_target_timeline)));
>> +                    recoveryTargetTLI = recovery_target_timeline;
>>                      recoveryTargetIsLatest = false;
>
> So, now we have a recoveryTargetTLI and recovery_target_timeline
> variable? Really? Why do we need recoveryTargetTLI at all now?

Looks like we still do need both of them.  The initial value of
recoveryTargetTLI is derived from pg_control, but later it can be
overriden by this setting.

However, if the recovery_target_timeline was "latest" we need to find
the latest TLI, based on the initial value from pg_control.  But we
can't set final recoveryTargetTLI value in the GUC assign hook, because
we might need to fetch some history files first.

>> +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;
>> +}
>> +
>
> I don't think it's correct to do such hangups in the assign hook - you
> have no ideas in which order they will be called and such. Imo that
> should happen at startup, like we also do it for other interdependent
> variables like wal_buffers.

Yeah, that looked weird.  Moved to StartupXLOG().

I disliked the strtoul handling in the earlier version of the patch,
especially given that with the base=0 it can parse 0x-prefixed hex
strings.  I would rather error out on non-hex digit instead of stopping
and calling it OK.  This change is included in the new version.

Should we really allow specifying negative values for XID/timeline?
Right now it will happily consume "-1" for recovery_target_xid and
complain if it's out of range, like this:

LOG:  starting point-in-time recovery to XID 4294967295
LOG:  invalid primary checkpoint record
LOG:  invalid secondary checkpoint record

Allowing negative values makes even less sense for timelines, IMO.

--
Alex

>From de59408e524e3818a7cea98a7c1f049e09eb9f79 Mon Sep 17 00:00:00 2001
From: Alex Shulgin <a...@commandprompt.com>
Date: Fri, 21 Nov 2014 12:22:22 +0300
Subject: [PATCH] DRAFT: rebased recovery_guc_v5.2.patch

---
 contrib/pg_archivecleanup/pg_archivecleanup.c   |   2 +-
 contrib/pg_standby/pg_standby.c                 |   2 +-
 doc/src/sgml/backup.sgml                        |  40 +-
 doc/src/sgml/config.sgml                        | 495 ++++++++++++++++++++++++
 doc/src/sgml/filelist.sgml                      |   1 -
 doc/src/sgml/func.sgml                          |   2 +-
 doc/src/sgml/high-availability.sgml             |  39 +-
 doc/src/sgml/pgarchivecleanup.sgml              |   6 +-
 doc/src/sgml/pgstandby.sgml                     |   4 +-
 doc/src/sgml/postgres.sgml                      |   1 -
 doc/src/sgml/recovery-config.sgml               | 460 ----------------------
 doc/src/sgml/ref/pg_basebackup.sgml             |   8 +-
 doc/src/sgml/release-9.1.sgml                   |   7 +-
 doc/src/sgml/release-9.4.sgml                   |  12 +-
 doc/src/sgml/release.sgml                       |   4 +-
 src/backend/Makefile                            |   4 +-
 src/backend/access/transam/recovery.conf.sample | 153 --------
 src/backend/access/transam/xlog.c               | 405 ++++++-------------
 src/backend/access/transam/xlogarchive.c        |   4 +-
 src/backend/commands/extension.c                |   2 +-
 src/backend/utils/misc/guc.c                    | 290 ++++++++++++++
 src/backend/utils/misc/postgresql.conf.sample   |  34 +-
 src/bin/pg_basebackup/pg_basebackup.c           | 206 +---------
 src/bin/pg_ctl/pg_ctl.c                         |   8 +-
 src/include/access/xlog.h                       |  17 +
 src/include/utils/guc_tables.h                  |   2 +
 src/port/quotes.c                               |   3 +-
 27 files changed, 1039 insertions(+), 1172 deletions(-)
 delete mode 100644 doc/src/sgml/recovery-config.sgml
 delete mode 100644 src/backend/access/transam/recovery.conf.sample

diff --git a/contrib/pg_archivecleanup/pg_archivecleanup.c b/contrib/pg_archivecleanup/pg_archivecleanup.c
index 97225a8..b5c1059 100644
--- a/contrib/pg_archivecleanup/pg_archivecleanup.c
+++ b/contrib/pg_archivecleanup/pg_archivecleanup.c
@@ -255,7 +255,7 @@ usage(void)
 	printf("  -x EXT         clean up files if they have this extension\n");
 	printf("  -?, --help     show this help, then exit\n");
 	printf("\n"
-		   "For use as archive_cleanup_command in recovery.conf when standby_mode = on:\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");
diff --git a/contrib/pg_standby/pg_standby.c b/contrib/pg_standby/pg_standby.c
index d6b1692..a6a2592 100644
--- a/contrib/pg_standby/pg_standby.c
+++ b/contrib/pg_standby/pg_standby.c
@@ -527,7 +527,7 @@ usage(void)
 	printf("  -w MAXWAITTIME     max seconds to wait for a file (0=no limit) (default=0)\n");
 	printf("  -?, --help         show this help, then exit\n");
 	printf("\n"
-		   "Main intended use as restore_command in recovery.conf:\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");
diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index 07ca0dc..7b66e31 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -1046,10 +1046,17 @@ 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.
+     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 file called <filename>standby.enabled</> 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>
    </listitem>
    <listitem>
@@ -1058,10 +1065,9 @@ SELECT pg_stop_backup();
      proceed to read through the archived WAL files it needs.  Should the
      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.
+     of the recovery process, the server will delete
+     <filename>standby.enabled</> (to prevent accidentally re-entering
+     recovery mode later) and then commence normal database operations.
     </para>
    </listitem>
    <listitem>
@@ -1075,12 +1081,11 @@ 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</>,
+    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
@@ -1142,7 +1147,7 @@ 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 <link linkend="recovery-target-settings">stopping point</link> in <filename>recovery.conf</>.  You can specify
+    required <link linkend="runtime-config-wal-recovery-target">stopping point</link> 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
@@ -1239,8 +1244,9 @@ 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
+    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>
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index ab8c263..d1c1353 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -2540,6 +2540,393 @@ include_dir 'conf.d'
 
      </variablelist>
     </sect2>
+   </sect1>
+
+   <sect1 id="runtime-config-recovery">
+    <title>Recovery</title>
+
+    <sect2 id="runtime-config-wal-archive-recovery">
+     <title>Archive Recovery</title>
+
+     <para>
+      These settings control the behavior of server when put in recovery by
+      creating a recovery trigger file <filename>standby.enabled</> in data
+      folder. Those parameters are not used if server is not in recovery.
+     </para>
+
+     <variablelist>
+      <varlistentry id="guc-restore-command" xreflabel="restore_command">
+       <term><varname>restore_command</varname> (<type>string</type>)
+       <indexterm>
+        <primary><varname>restore_command</> configuration parameter</primary>
+       </indexterm>
+       </term>
+       <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>)
+       <indexterm>
+         <primary><varname>archive_cleanup_command</> configuration parameter</primary>
+       </indexterm>
+       </term>
+       <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>)
+       <indexterm>
+         <primary><varname>recovery_end_command</> configuration parameter</primary>
+       </indexterm>
+       </term>
+       <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>
+
+      <varlistentry id="min-recovery-apply-delay" xreflabel="min_recovery_apply_delay">
+       <term><varname>min_recovery_apply_delay</varname> (<type>integer</type>)
+       <indexterm>
+         <primary><varname>min_recovery_apply_delay</> recovery parameter</primary>
+       </indexterm>
+       </term>
+       <listitem>
+        <para>
+         By default, a standby server keeps restoring WAL records from the
+         primary as soon as possible. It may be useful to have a time-delayed
+         copy of the data, offering various options to correct data loss errors.
+         This parameter allows you to delay recovery by a fixed period of time,
+         specified in milliseconds if no unit is specified.  For example, if
+         you set this parameter to <literal>5min</literal>, the standby will
+         replay each transaction commit only when the system time on the standby
+         is at least five minutes past the commit time reported by the master.
+        </para>
+        <para>
+         It is possible that the replication delay between servers exceeds the
+         value of this parameter, in which case no delay is added.
+         Note that the delay is calculated between the WAL timestamp as written
+         on master and the time on the current standby. Delays
+         in transfer because of networks or cascading replication configurations
+         may reduce the actual wait time significantly. If the system
+         clocks on master and standby are not synchronised, this may lead to
+         recovery applying records earlier than expected but is not a major issue
+         because the useful settings of the parameter are much larger than
+         typical time deviation between the servers. Be careful to allow for
+         different timezone settings on master and standby.
+        </para>
+        <para>
+         The delay occurs only on WAL records for COMMIT and Restore Points.
+         Other records may be replayed earlier than the specified delay, which
+         is not an issue for MVCC though may potentially increase the number
+         of recovery conflicts generated.
+        </para>
+        <para>
+         The delay occurs until the standby is promoted or triggered. After that
+         the standby will end recovery without further waiting.
+        </para>
+        <para>
+         This parameter is intended for use with streaming replication deployments,
+         however, if the parameter is specified it will be honoured in all cases.
+         Synchronous replication is not affected by this setting because there is
+         not yet any setting to request synchronous apply of transaction commits.
+         <varname>hot_standby_feedback</> will be delayed by use of this feature
+         which could lead to bloat on the master; use both together with care.
+        </para>
+       </listitem>
+      </varlistentry>
+     </variablelist>
+    </sect2>
+
+    <sect2 id="runtime-config-wal-recovery-target">
+     <title>Recovery Target</title>
+
+     <variablelist>
+
+      <varlistentry id="guc-recovery-target" xreflabel="recovery_target_name">
+       <term><varname>recovery_target</varname><literal> = 'immediate'</literal>
+       <indexterm>
+         <primary><varname>recovery_target</> recovery parameter</primary>
+       </indexterm>
+       </term>
+       <listitem>
+        <para>
+         This parameter specifies that recovery should end as soon as a
+         consistent state is reached, i.e. as early as possible. When restoring
+         from an online backup, this means the point where taking the backup
+         ended.
+        </para>
+        <para>
+         Technically, this is a string parameter, but <literal>'immediate'</>
+         is currently the only allowed value.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-recovery-target-name" xreflabel="recovery_target_name">
+       <term><varname>recovery_target_name</varname> (<type>string</type>)
+       <indexterm>
+        <primary><varname>recovery_target_name</> configuration parameter</primary>
+       </indexterm>
+       </term>
+       <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>)
+       <indexterm>
+        <primary><varname>recovery_target_time</> configuration parameter</primary>
+       </indexterm>
+       </term>
+       <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>)
+       <indexterm>
+        <primary><varname>recovery_target_xid</> configuration parameter</primary>
+       </indexterm>
+       </term>
+       <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>)
+       <indexterm>
+        <primary><varname>recovery_target_inclusive</> configuration parameter</primary>
+       </indexterm>
+       </term>
+       <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>)
+       <indexterm>
+        <primary><varname>recovery_target_timeline</> configuration parameter</primary>
+       </indexterm>
+       </term>
+       <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>)
+       <indexterm>
+        <primary><varname>pause_at_recovery_target</> configuration parameter</primary>
+       </indexterm>
+       </term>
+       <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>
+
+    <sect2 id="runtime-config-recovery-conf-substitute">
+     <title>Migration from recovery.conf</title>
+
+     <para>
+      Prior <productname>PostgreSQL</> 9.2, all the recovery parameters had
+      to be specified in a configuration file called <filename>recovery.conf</>
+      located at the root of data folder of server. Servers running
+      <productname>PostgreSQL</> 9.3 and above return an error if
+      <filename>recovery.conf</> is found in data folder.
+     </para>
+
+     <para>
+      <filename>postgresql.conf</> provides two parameters allowing the
+      inclusion of external configuration files by either setting
+      <literal>include_if_exists</> to include a given file or <literal>include_dir</>
+      to include a directory containing a set of files configuration files.
+      In order to migrate an existing <filename>recovery.conf</> used with
+      a server whose version is lower than 9.2, set one of those parameters to
+      include it correctly. It is also necessary to rename <filename>recovery.conf</>
+      to a new name if the file included is located at root of data folder.
+     </para>
+
+    </sect2>
 
    </sect1>
 
@@ -2789,6 +3176,114 @@ include_dir 'conf.d'
 
     <variablelist>
 
+     <varlistentry id="guc-standby-mode" xreflabel="standby_mode">
+      <term><varname>standby_mode</varname> (<type>boolean</type>)
+      <indexterm>
+       <primary><varname>standby_mode</> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        Specifies whether to start the <productname>PostgreSQL</> server as
+        a standby when the file called <filename>standby.enabled</> 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 file <filename>standby.enabled</> exists.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-primary-conninfo" xreflabel="primary_conninfo">
+      <term><varname>primary_conninfo</varname> (<type>string</type>)
+      <indexterm>
+        <primary><varname>primary_conninfo</> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <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="primary-slot-name" xreflabel="primary_slot_name">
+      <term><varname>primary_slot_name</varname> (<type>string</type>)
+      <indexterm>
+        <primary><varname>primary_slot_name</> recovery parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        Optionally specifies an existing replication slot to be used when
+        connecting to the primary via streaming replication to control
+        resource removal on the upstream node
+        (see <xref linkend="streaming-replication-slots">).
+        This setting has no effect if <varname>primary_conninfo</> is not
+        set.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-trigger-file" xreflabel="trigger_file">
+      <term><varname>trigger_file</varname> (<type>string</type>)
+      <indexterm>
+        <primary><varname>trigger_file</> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <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>)
       <indexterm>
diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml
index f03b72a..feff95f3 100644
--- a/doc/src/sgml/filelist.sgml
+++ b/doc/src/sgml/filelist.sgml
@@ -44,7 +44,6 @@
 <!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">
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 90a3460..73c5196 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -16322,7 +16322,7 @@ 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
+    <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.
diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml
index d249959..e7e88aa 100644
--- a/doc/src/sgml/high-availability.sgml
+++ b/doc/src/sgml/high-availability.sgml
@@ -591,7 +591,7 @@ 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
+    (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
@@ -660,8 +660,8 @@ 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
+    trigger file <filename>standby.enabled</> 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
@@ -697,7 +697,7 @@ 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
+    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
@@ -708,7 +708,7 @@ protocol to make nodes agree on a serializable transactional order.
    </para>
 
    <para>
-    A simple example of a <filename>recovery.conf</> is:
+    A simple example of standby settings is:
 <programlisting>
 standby_mode = 'on'
 primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
@@ -766,8 +766,8 @@ 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
+    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
@@ -827,15 +827,14 @@ 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.
+     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 add the following line to the <filename>recovery.conf</> file on the
-     standby:
+     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
@@ -1292,8 +1291,8 @@ primary_slot_name = 'node_a_slot'
    <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
+    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
@@ -1338,8 +1337,7 @@ primary_slot_name = 'node_a_slot'
     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
+    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
@@ -1426,8 +1424,14 @@ if (!triggered)
      </listitem>
      <listitem>
       <para>
+       Create a file called <filename>standby.enabled</> in the standby's
+       cluster data directory to trigger the recovery.
+      </para>
+     </listitem>
+     <listitem>
+      <para>
        Begin recovery on the standby server from the local WAL
-       archive, using a <filename>recovery.conf</> that specifies a
+       archive, specifying a
        <varname>restore_command</> that waits as described
        previously (see <xref linkend="backup-pitr-recovery">).
       </para>
@@ -1923,9 +1927,8 @@ 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.
+    If <varname>hot_standby</> is turned <literal>on</> and there is a file
+    <filename>standby.enabled</> 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
diff --git a/doc/src/sgml/pgarchivecleanup.sgml b/doc/src/sgml/pgarchivecleanup.sgml
index fdf0cbb..cf5d229 100644
--- a/doc/src/sgml/pgarchivecleanup.sgml
+++ b/doc/src/sgml/pgarchivecleanup.sgml
@@ -38,8 +38,8 @@
 
   <para>
    To configure a standby
-   server to use <application>pg_archivecleanup</>, put this into its
-   <filename>recovery.conf</filename> configuration file:
+   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>
@@ -47,7 +47,7 @@ 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
+   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
diff --git a/doc/src/sgml/pgstandby.sgml b/doc/src/sgml/pgstandby.sgml
index fb3f32e..545cf85 100644
--- a/doc/src/sgml/pgstandby.sgml
+++ b/doc/src/sgml/pgstandby.sgml
@@ -46,8 +46,8 @@
 
   <para>
    To configure a standby
-   server to use <application>pg_standby</>, put this into its
-   <filename>recovery.conf</filename> configuration file:
+   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>
diff --git a/doc/src/sgml/postgres.sgml b/doc/src/sgml/postgres.sgml
index a648a4c..bce9acd 100644
--- a/doc/src/sgml/postgres.sgml
+++ b/doc/src/sgml/postgres.sgml
@@ -155,7 +155,6 @@
   &maintenance;
   &backup;
   &high-availability;
-  &recovery-config;
   &monitoring;
   &diskusage;
   &wal;
diff --git a/doc/src/sgml/recovery-config.sgml b/doc/src/sgml/recovery-config.sgml
deleted file mode 100644
index 0f1ff34..0000000
--- a/doc/src/sgml/recovery-config.sgml
+++ /dev/null
@@ -1,460 +0,0 @@
-<!-- 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>)
-      <indexterm>
-        <primary><varname>restore_command</> recovery parameter</primary>
-      </indexterm>
-      </term>
-      <listitem>
-       <para>
-        The local 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>
-        An exception is that if the command was terminated by a signal (other
-        than <systemitem>SIGTERM</systemitem>, which is used as part of a
-        database server shutdown) or an error by the shell (such as command
-        not found), then recovery will abort and the server will not start up.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry id="archive-cleanup-command" xreflabel="archive_cleanup_command">
-      <term><varname>archive_cleanup_command</varname> (<type>string</type>)
-      <indexterm>
-        <primary><varname>archive_cleanup_command</> recovery parameter</primary>
-      </indexterm>
-      </term>
-      <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 nonzero exit status then a warning log
-        message will be written.  An exception is that if the command was
-        terminated by a signal or an error by the shell (such as command not
-        found), a fatal error will be raised.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry id="recovery-end-command" xreflabel="recovery_end_command">
-      <term><varname>recovery_end_command</varname> (<type>string</type>)
-      <indexterm>
-        <primary><varname>recovery_end_command</> recovery parameter</primary>
-      </indexterm>
-      </term>
-      <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 nonzero 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 or an error by the shell (such as command not found), the
-        database will not proceed with startup.
-       </para>
-      </listitem>
-     </varlistentry>
-
-    </variablelist>
-
-  </sect1>
-
-  <sect1 id="recovery-target-settings">
-
-    <title>Recovery Target Settings</title>
-     <para>
-      By default, recovery will recover to the end of the WAL log. The
-      following parameters can be used to specify an earlier stopping point.
-      At most one of <varname>recovery_target</>,
-      <varname>recovery_target_name</>, <varname>recovery_target_time</>, or
-      <varname>recovery_target_xid</> can be specified.
-     </para>
-     <variablelist>
-
-     <varlistentry id="recovery-target" xreflabel="recovery_target_name">
-      <term><varname>recovery_target</varname><literal> = 'immediate'</literal>
-      <indexterm>
-        <primary><varname>recovery_target</> recovery parameter</primary>
-      </indexterm>
-      </term>
-      <listitem>
-       <para>
-        This parameter specifies that recovery should end as soon as a
-        consistent state is reached, i.e. as early as possible. When restoring
-        from an online backup, this means the point where taking the backup
-        ended.
-       </para>
-       <para>
-        Technically, this is a string parameter, but <literal>'immediate'</>
-        is currently the only allowed value.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry id="recovery-target-name" xreflabel="recovery_target_name">
-      <term><varname>recovery_target_name</varname> (<type>string</type>)
-      <indexterm>
-        <primary><varname>recovery_target_name</> recovery parameter</primary>
-      </indexterm>
-      </term>
-      <listitem>
-       <para>
-        This parameter specifies the named restore point, created with
-        <function>pg_create_restore_point()</> to which recovery will proceed.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry id="recovery-target-time" xreflabel="recovery_target_time">
-      <term><varname>recovery_target_time</varname> (<type>timestamp</type>)
-      <indexterm>
-        <primary><varname>recovery_target_time</> recovery parameter</primary>
-      </indexterm>
-      </term>
-      <listitem>
-       <para>
-        This parameter specifies the time stamp up to which recovery
-        will proceed.
-        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>)
-      <indexterm>
-        <primary><varname>recovery_target_xid</> recovery parameter</primary>
-      </indexterm>
-      </term>
-      <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.
-        The precise stopping point is also influenced by
-        <xref linkend="recovery-target-inclusive">.
-       </para>
-      </listitem>
-     </varlistentry>
-     </variablelist>
-     <para>
-       The following options further specify the recovery target, and affect
-       what happens when the target is reached:
-     </para>
-
-     <variablelist>
-
-     <varlistentry id="recovery-target-inclusive"
-                   xreflabel="recovery_target_inclusive">
-      <term><varname>recovery_target_inclusive</varname> (<type>boolean</type>)
-      <indexterm>
-        <primary><varname>recovery_target_inclusive</> recovery parameter</primary>
-      </indexterm>
-      </term>
-      <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>)
-      <indexterm>
-        <primary><varname>recovery_target_timeline</> recovery parameter</primary>
-      </indexterm>
-      </term>
-      <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>)
-      <indexterm>
-        <primary><varname>pause_at_recovery_target</> recovery parameter</primary>
-      </indexterm>
-      </term>
-      <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>)
-        <indexterm>
-          <primary><varname>standby_mode</> recovery parameter</primary>
-        </indexterm>
-        </term>
-        <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>)
-        <indexterm>
-          <primary><varname>primary_conninfo</> recovery parameter</primary>
-        </indexterm>
-        </term>
-        <listitem>
-         <para>
-          Specifies a connection string to be used for the standby server
-          to connect with the primary. This string is in the format
-          described in <xref linkend="libpq-connstring">. 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 suitably-privileged role
-          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="primary-slot-name" xreflabel="primary_slot_name">
-        <term><varname>primary_slot_name</varname> (<type>string</type>)
-        <indexterm>
-          <primary><varname>primary_slot_name</> recovery parameter</primary>
-        </indexterm>
-        </term>
-        <listitem>
-         <para>
-          Optionally specifies an existing replication slot to be used when
-          connecting to the primary via streaming replication to control
-          resource removal on the upstream node
-          (see <xref linkend="streaming-replication-slots">).
-          This setting has no effect if <varname>primary_conninfo</> is not
-          set.
-         </para>
-        </listitem>
-       </varlistentry>
-       <varlistentry id="trigger-file" xreflabel="trigger_file">
-        <term><varname>trigger_file</varname> (<type>string</type>)
-        <indexterm>
-          <primary><varname>trigger_file</> recovery parameter</primary>
-        </indexterm>
-        </term>
-        <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>
-
-     <varlistentry id="recovery-min-apply-delay" xreflabel="recovery_min_apply_delay">
-      <term><varname>recovery_min_apply_delay</varname> (<type>integer</type>)
-      <indexterm>
-        <primary><varname>recovery_min_apply_delay</> recovery parameter</primary>
-      </indexterm>
-      </term>
-      <listitem>
-       <para>
-        By default, a standby server restores WAL records from the
-        primary as soon as possible. It may be useful to have a time-delayed
-        copy of the data, offering various options to correct data loss errors.
-        This parameter allows you to delay recovery by a fixed period of time,
-        specified in milliseconds if no unit is specified.  For example, if
-        you set this parameter to <literal>5min</literal>, the standby will
-        replay each transaction commit only when the system time on the standby
-        is at least five minutes past the commit time reported by the master.
-       </para>
-       <para>
-        It is possible that the replication delay between servers exceeds the
-        value of this parameter, in which case no delay is added.
-        Note that the delay is calculated between the WAL timestamp as written
-        on master and the time on the current standby. Delays
-        in transfer because of networks or cascading replication configurations
-        may reduce the actual wait time significantly. If the system
-        clocks on master and standby are not synchronized, this may lead to
-        recovery applying records earlier than expected; but that is not a
-        major issue because useful settings of the parameter are much larger
-        than typical time deviations between servers. Be careful to allow for
-        different timezone settings on master and standby.
-       </para>
-       <para>
-        The delay occurs only on WAL records for COMMIT and Restore Points.
-        Other records may be replayed earlier than the specified delay, which
-        is not an issue for MVCC though it may potentially increase the number
-        of recovery conflicts generated.
-       </para>
-       <para>
-        The delay occurs until the standby is promoted or triggered. After that
-        the standby will end recovery without further waiting.
-       </para>
-       <para>
-        This parameter is intended for use with streaming replication deployments,
-        however, if the parameter is specified it will be honored in all cases.
-        Synchronous replication is not affected by this setting because there is
-        not yet any setting to request synchronous apply of transaction commits.
-        <varname>hot_standby_feedback</> will be delayed by use of this feature
-        which could lead to bloat on the master; use both together with care.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     </variablelist>
-   </sect1>
-
-</chapter>
diff --git a/doc/src/sgml/ref/pg_basebackup.sgml b/doc/src/sgml/ref/pg_basebackup.sgml
index 642fccf..06a91a1 100644
--- a/doc/src/sgml/ref/pg_basebackup.sgml
+++ b/doc/src/sgml/ref/pg_basebackup.sgml
@@ -211,13 +211,13 @@ PostgreSQL documentation
 
      <varlistentry>
       <term><option>-R</option></term>
-      <term><option>--write-recovery-conf</option></term>
+      <term><option>--write-standby-enable</option></term>
       <listitem>
 
        <para>
-        Write a minimal <filename>recovery.conf</filename> in the output directory (or into
-        the base archive file when using tar format) to ease setting
-        up a standby server.
+        Write a minimal <filename>standby.enabled</filename> in the output
+        directory (or into the base archive file when using tar format)
+        to ease setting up a standby server.
        </para>
 
       </listitem>
diff --git a/doc/src/sgml/release-9.1.sgml b/doc/src/sgml/release-9.1.sgml
index 4f86b64..e899e7e 100644
--- a/doc/src/sgml/release-9.1.sgml
+++ b/doc/src/sgml/release-9.1.sgml
@@ -6302,7 +6302,7 @@
       <listitem>
        <para>
         Add <filename>recovery.conf</> setting <link
-        linkend="pause-at-recovery-target"><varname>pause_at_recovery_target</></link>
+        linkend="guc-pause-at-recovery-target"><varname>pause_at_recovery_target</></link>
         to pause recovery at target (Simon Riggs)
        </para>
 
@@ -6322,7 +6322,7 @@
        <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>.
+        <link linkend="guc-recovery-target-name"><varname>recovery_target_name</></link>.
        </para>
       </listitem>
 
@@ -6354,8 +6354,7 @@
 
       <listitem>
        <para>
-        Allow <link
-        linkend="recovery-config"><filename>recovery.conf</></link>
+        Allow <filename>recovery.conf</>
         to use the same quoting behavior as <filename>postgresql.conf</>
         (Dimitri Fontaine)
        </para>
diff --git a/doc/src/sgml/release-9.4.sgml b/doc/src/sgml/release-9.4.sgml
index a249b3f..120fede 100644
--- a/doc/src/sgml/release-9.4.sgml
+++ b/doc/src/sgml/release-9.4.sgml
@@ -335,7 +335,7 @@
 
     <listitem>
      <para>
-      Use the last specified <xref linkend="recovery-target"> if multiple
+      Use the last specified <xref linkend="guc-recovery-target"> if multiple
       values are specified (Heikki Linnakangas)
      </para>
     </listitem>
@@ -349,7 +349,7 @@
      <para>
       User commands that did their own quote preservation might need
       adjustment.  This is likely to be an issue for commands used in
-      <xref linkend="guc-archive-command">, <xref linkend="restore-command">,
+      <xref linkend="guc-archive-command">, <xref linkend="guc-restore-command">,
       and <link linkend="sql-copy"><command>COPY TO/FROM PROGRAM</></link>.
      </para>
     </listitem>
@@ -993,8 +993,8 @@
 
       <listitem>
        <para>
-        Add <link linkend="recovery-config"><filename>recovery.conf</></link>
-        parameter <xref linkend="recovery-min-apply-delay">
+        Add <link linkend="config-setting"><filename>postgresql.conf</></link>
+        parameter <xref linkend="min-recovery-apply-delay">
         to delay replication (Robert Haas, Fabr&iacute;zio de Royes Mello,
         Simon Riggs)
        </para>
@@ -1007,7 +1007,7 @@
 
       <listitem>
        <para>
-        Add <xref linkend="recovery-target">
+        Add <xref linkend="guc-recovery-target">
         option <option>immediate</> to stop <link
         linkend="wal"><acronym>WAL</></link> recovery as soon as a
         consistent state is reached (MauMau, Heikki Linnakangas)
@@ -1044,7 +1044,7 @@
       <listitem>
        <para>
         Report failure return codes from <link
-        linkend="archive-recovery-settings">external recovery commands</>
+        linkend="runtime-config-wal-archive-recovery">external recovery commands</>
         (Peter Eisentraut)
        </para>
       </listitem>
diff --git a/doc/src/sgml/release.sgml b/doc/src/sgml/release.sgml
index 8385220..1b983fa 100644
--- a/doc/src/sgml/release.sgml
+++ b/doc/src/sgml/release.sgml
@@ -5,8 +5,8 @@ Typical markup:
 
 &<>                             use & escapes
 PostgreSQL                      <productname>
-postgresql.conf, pg_hba.conf,
-        recovery.conf           <filename>
+postgresql.conf, pg_hba.conf
+        standby.enabled         <filename>
 [A-Z][A-Z_ ]+[A-Z_]             <command>, <literal>, <envar>, <acronym>
 [A-Za-z_][A-Za-z0-9_]+()        <function>
 -[-A-Za-z_]+                    <option>
diff --git a/src/backend/Makefile b/src/backend/Makefile
index 870a022..638d0c5 100644
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -215,7 +215,6 @@ endif
 	$(INSTALL_DATA) $(srcdir)/libpq/pg_hba.conf.sample '$(DESTDIR)$(datadir)/pg_hba.conf.sample'
 	$(INSTALL_DATA) $(srcdir)/libpq/pg_ident.conf.sample '$(DESTDIR)$(datadir)/pg_ident.conf.sample'
 	$(INSTALL_DATA) $(srcdir)/utils/misc/postgresql.conf.sample '$(DESTDIR)$(datadir)/postgresql.conf.sample'
-	$(INSTALL_DATA) $(srcdir)/access/transam/recovery.conf.sample '$(DESTDIR)$(datadir)/recovery.conf.sample'
 
 install-bin: postgres $(POSTGRES_IMP) installdirs
 	$(INSTALL_PROGRAM) postgres$(X) '$(DESTDIR)$(bindir)/postgres$(X)'
@@ -272,8 +271,7 @@ endif
 	$(MAKE) -C tsearch uninstall-data
 	rm -f '$(DESTDIR)$(datadir)/pg_hba.conf.sample' \
 	      '$(DESTDIR)$(datadir)/pg_ident.conf.sample' \
-              '$(DESTDIR)$(datadir)/postgresql.conf.sample' \
-	      '$(DESTDIR)$(datadir)/recovery.conf.sample'
+              '$(DESTDIR)$(datadir)/postgresql.conf.sample'
 
 
 ##########################################################################
diff --git a/src/backend/access/transam/recovery.conf.sample b/src/backend/access/transam/recovery.conf.sample
deleted file mode 100644
index 7657df3..0000000
--- a/src/backend/access/transam/recovery.conf.sample
+++ /dev/null
@@ -1,153 +0,0 @@
-# -------------------------------
-# 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
-#---------------------------------------------------------------------------
-#
-# restore_command
-#
-# specifies the shell command that is executed to copy log files
-# back from archival storage.  The command string may contain %f,
-# which is replaced by the name of the desired log file, and %p,
-# which is replaced by the absolute path to copy the log file to.
-#
-# This parameter is *required* for an archive recovery, but optional
-# for streaming replication.
-#
-# It is important that the command return nonzero exit status on failure.
-# The command *will* be asked for log files that are not present in the
-# archive; it must return nonzero when so asked.
-#
-# NOTE that the basename of %p will be different from %f; do not
-# expect them to be interchangeable.
-#
-#restore_command = ''		# e.g. 'cp /mnt/server/archivedir/%f %p'
-#
-#
-# archive_cleanup_command
-#
-# specifies an optional shell command to execute at every restartpoint.
-# This can be useful for cleaning up the archive of a standby server.
-#
-#archive_cleanup_command = ''
-#
-# recovery_end_command
-#
-# specifies an optional shell command to execute at completion of recovery.
-# This can be useful for cleaning up after the restore_command.
-#
-#recovery_end_command = ''
-#
-#---------------------------------------------------------------------------
-# RECOVERY TARGET PARAMETERS
-#---------------------------------------------------------------------------
-#
-# By default, recovery will rollforward to the end of the WAL log.
-# If you want to stop rollforward at a specific point, you
-# must set a recovery target.
-#
-# You may set a recovery target either by transactionId, by name,
-# or by timestamp. Recovery may either include or exclude the
-# transaction(s) with the recovery target value (ie, stop either
-# just after or just before the given target, respectively).
-#
-#
-#recovery_target_name = ''	# e.g. 'daily backup 2011-01-26'
-#
-#recovery_target_time = ''	# e.g. '2004-07-14 22:39:00 EST'
-#
-#recovery_target_xid = ''
-#
-#recovery_target_inclusive = true
-#
-#
-# Alternatively, you can request stopping as soon as a consistent state
-# is reached, by uncommenting this option.
-#
-#recovery_target = 'immediate'
-#
-#
-# If you want to recover into a timeline other than the "main line" shown in
-# pg_control, specify the timeline number here, or write 'latest' to get
-# the latest branch for which there's a history file.
-#
-#recovery_target_timeline = 'latest'
-#
-#
-# If pause_at_recovery_target is enabled, recovery will pause when
-# the recovery target is reached. The pause state will continue until
-# pg_xlog_replay_resume() is called. This setting has no effect if
-# hot standby is not enabled, or if no recovery target is set.
-#
-#pause_at_recovery_target = true
-#
-#---------------------------------------------------------------------------
-# STANDBY SERVER PARAMETERS
-#---------------------------------------------------------------------------
-#
-# standby_mode
-#
-# When standby_mode is enabled, the PostgreSQL server will work as a
-# standby. It will continuously wait for the additional XLOG records, using
-# restore_command and/or primary_conninfo.
-#
-#standby_mode = off
-#
-# primary_conninfo
-#
-# If set, the PostgreSQL server will try to connect to the primary using this
-# connection string and receive XLOG records continuously.
-#
-#primary_conninfo = ''		# e.g. 'host=localhost port=5432'
-#
-# If set, the PostgreSQL server will use the specified replication slot when
-# connecting to the primary via streaming replication to control resource
-# removal on the upstream node. This setting has no effect if primary_conninfo
-# is not set.
-#
-#primary_slot_name = ''
-#
-# By default, a standby server keeps restoring XLOG records from the
-# primary indefinitely. If you want to stop the standby mode, finish recovery
-# and open the system in read/write mode, specify a path to a trigger file.
-# The server will poll the trigger file path periodically and start as a
-# primary server when it's found.
-#
-#trigger_file = ''
-#
-# By default, a standby server restores XLOG records from the primary as
-# soon as possible. If you want to explicitly delay the replay of committed
-# transactions from the master, specify a minimum apply delay. For example,
-# if you set this parameter to 5min, the standby will replay each transaction
-# commit only when the system time on the standby is at least five minutes
-# past the commit time reported by the master.
-#
-#recovery_min_apply_delay = 0
-#
-#---------------------------------------------------------------------------
-# HOT STANDBY PARAMETERS
-#---------------------------------------------------------------------------
-#
-# Hot Standby related parameters are listed in postgresql.conf
-#
-#---------------------------------------------------------------------------
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 2059bbe..2fe96d1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -71,11 +71,12 @@
 extern uint32 bootstrap_data_checksum_version;
 
 /* File path names (all relative to $PGDATA) */
-#define RECOVERY_COMMAND_FILE	"recovery.conf"
-#define RECOVERY_COMMAND_DONE	"recovery.done"
+#define RECOVERY_ENABLE_FILE	"standby.enabled"
 #define PROMOTE_SIGNAL_FILE		"promote"
 #define FALLBACK_PROMOTE_SIGNAL_FILE "fallback_promote"
 
+/* recovery.conf is not supported anymore */
+#define RECOVERY_COMMAND_FILE	"recovery.conf"
 
 /* User-settable parameters */
 int			CheckPointSegments = 3;
@@ -207,7 +208,7 @@ static int	LocalXLogInsertAllowed = -1;
 
 /*
  * When ArchiveRecoveryRequested is set, archive recovery was requested,
- * ie. recovery.conf file was present. When InArchiveRecovery is set, we are
+ * ie. standby.enabled file was present. When InArchiveRecovery is set, we are
  * currently recovering using offline XLOG archives. These variables are only
  * valid in the startup process.
  *
@@ -222,27 +223,29 @@ 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 */
-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;
-static int	recovery_min_apply_delay = 0;
-static TimestampTz recoveryDelayUntilTime;
-
-/* options taken from recovery.conf for XLOG streaming */
-static bool StandbyModeRequested = false;
-static char *PrimaryConnInfo = NULL;
-static char *PrimarySlotName = NULL;
-static char *TriggerFile = NULL;
+char	   *restore_command = NULL;
+char	   *archive_cleanup_command = NULL;
+char	   *recovery_end_command = NULL;
+char	   *primary_conninfo = NULL;
+char	   *primary_slot_name = NULL;
+char	   *trigger_file = NULL;
+char			   *recovery_target_string = NULL;
+RecoveryTargetType	recovery_target = RECOVERY_TARGET_UNSET;
+char			   *recovery_target_xid_string = NULL;
+TransactionId		recovery_target_xid = InvalidTransactionId;
+char			   *recovery_target_time_string = NULL;
+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;
+int		recovery_min_apply_delay = 0;
+static TimestampTz	recoveryDelayUntilTime;
 
 /* are we currently in standby mode? */
-bool		StandbyMode = false;
+bool StandbyModeRequested = false;
+bool StandbyMode = false;
 
 /* whether request for fast promotion has been made yet */
 static bool fast_promote = false;
@@ -547,12 +550,6 @@ typedef struct XLogCtlData
 	TimeLineID	PrevTimeLineID;
 
 	/*
-	 * archiveCleanupCommand is read from recovery.conf but needs to be in
-	 * shared memory so that the checkpointer process can access it.
-	 */
-	char		archiveCleanupCommand[MAXPGPATH];
-
-	/*
 	 * SharedRecoveryInProgress indicates if we're still in crash or archive
 	 * recovery.  Protected by info_lck.
 	 */
@@ -755,7 +752,7 @@ static bool holdingAllLocks = false;
 static MemoryContext walDebugCxt = NULL;
 #endif
 
-static void readRecoveryCommandFile(void);
+static void CheckStartingAsStandby(void);
 static void exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo);
 static bool recoveryStopsBefore(XLogReaderState *record);
 static bool recoveryStopsAfter(XLogReaderState *record);
@@ -4639,228 +4636,45 @@ str_time(pg_time_t tnow)
  * The file is parsed using the main configuration parser.
  */
 static void
-readRecoveryCommandFile(void)
+CheckStartingAsStandby(void)
 {
 	FILE	   *fd;
-	TimeLineID	rtli = 0;
-	bool		rtliGiven = false;
-	ConfigVariable *item,
-			   *head = NULL,
-			   *tail = NULL;
 
-	fd = AllocateFile(RECOVERY_COMMAND_FILE, "r");
+	/* Check the presence of recovery.conf, it is not supported anymore */
+	if (AllocateFile(RECOVERY_COMMAND_FILE, "r") != NULL)
+		ereport(FATAL,
+				(errmsg("\"%s\" is not supported anymore as a recovery method",
+						RECOVERY_COMMAND_FILE),
+				 errdetail("Refer to appropriate documentation about migration methods")));
+
+	/* Check the presence of file standby.enabled, the file triggering recovery */
+	fd = AllocateFile(RECOVERY_ENABLE_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)));
+				 errmsg("could not open recovery file trigger \"%s\": %m",
+						RECOVERY_ENABLE_FILE)));
 	}
-
-	/*
-	 * Since we're asking ParseConfigFp() to report errors as FATAL, there's
-	 * no need to check the return value.
-	 */
-	(void) ParseConfigFp(fd, RECOVERY_COMMAND_FILE, 0, FATAL, &head, &tail);
-
 	FreeFile(fd);
 
-	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)
-		{
-			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)
-		{
-			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") == 0)
-		{
-			if (strcmp(item->value, "immediate") == 0)
-				recoveryTarget = RECOVERY_TARGET_IMMEDIATE;
-			else
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-						 errmsg("invalid value for recovery parameter \"recovery_target\""),
-						 errhint("The only allowed value is \"immediate\".")));
-			ereport(DEBUG2,
-					(errmsg_internal("recovery_target = '%s'",
-									 item->value)));
-		}
-		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, &StandbyModeRequested))
-				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, "primary_slot_name") == 0)
-		{
-			ReplicationSlotValidateName(item->value, ERROR);
-			PrimarySlotName = pstrdup(item->value);
-			ereport(DEBUG2,
-					(errmsg_internal("primary_slot_name = '%s'",
-									 PrimarySlotName)));
-		}
-		else if (strcmp(item->name, "trigger_file") == 0)
-		{
-			TriggerFile = pstrdup(item->value);
-			ereport(DEBUG2,
-					(errmsg_internal("trigger_file = '%s'",
-									 TriggerFile)));
-		}
-		else if (strcmp(item->name, "recovery_min_apply_delay") == 0)
-		{
-			const char *hintmsg;
-
-			if (!parse_int(item->value, &recovery_min_apply_delay, GUC_UNIT_MS,
-						   &hintmsg))
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-						 errmsg("parameter \"%s\" requires a temporal value",
-								"recovery_min_apply_delay"),
-						 hintmsg ? errhint("%s", _(hintmsg)) : 0));
-			ereport(DEBUG2,
-					(errmsg_internal("recovery_min_apply_delay = '%s'", item->value)));
-		}
-		else
-			ereport(FATAL,
-					(errmsg("unrecognized recovery parameter \"%s\"",
-							item->name)));
-	}
-
 	/*
 	 * Check for compulsory parameters
 	 */
 	if (StandbyModeRequested)
 	{
-		if (PrimaryConnInfo == NULL && recoveryRestoreCommand == NULL)
+		if (primary_conninfo == NULL && restore_command == NULL)
 			ereport(WARNING,
-					(errmsg("recovery command file \"%s\" specified neither primary_conninfo nor restore_command",
-							RECOVERY_COMMAND_FILE),
+					(errmsg("Neither primary_conninfo nor restore_command specified"),
 					 errhint("The database server will regularly poll the pg_xlog subdirectory to check for files placed there.")));
 	}
 	else
 	{
-		if (recoveryRestoreCommand == NULL)
+		if (restore_command == NULL)
 			ereport(FATAL,
-					(errmsg("recovery command file \"%s\" must specify restore_command when standby mode is not enabled",
-							RECOVERY_COMMAND_FILE)));
+					(errmsg("restore_command must be specified when standby_mode is not enabled")));
 	}
 
 	/* Enable fetching from archive recovery area */
@@ -4872,16 +4686,17 @@ readRecoveryCommandFile(void)
 	 * command and set InArchiveRecovery, because we need to fetch timeline
 	 * history files from the archive.
 	 */
-	if (rtliGiven)
+	if (recovery_target_timeline_string != NULL)
 	{
-		if (rtli)
+		if (recovery_target_timeline != 0) /* not "", "0" or "latest" */
 		{
 			/* Timeline 1 does not have a history file, all else should */
-			if (rtli != 1 && !existsTimeLineHistory(rtli))
+			if (recovery_target_timeline != 1 &&
+				!existsTimeLineHistory(recovery_target_timeline))
 				ereport(FATAL,
 						(errmsg("recovery target timeline %u does not exist",
-								rtli)));
-			recoveryTargetTLI = rtli;
+								recovery_target_timeline)));
+			recoveryTargetTLI = recovery_target_timeline;
 			recoveryTargetIsLatest = false;
 		}
 		else
@@ -4891,8 +4706,6 @@ readRecoveryCommandFile(void)
 			recoveryTargetIsLatest = true;
 		}
 	}
-
-	FreeConfigVariables(head);
 }
 
 /*
@@ -4965,15 +4778,13 @@ exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo)
 	unlink(recoveryPath);		/* ignore any error */
 
 	/*
-	 * Rename the config file out of the way, so that we don't accidentally
-	 * re-enter archive recovery mode in a subsequent crash.
+	 * Remove file that triggered the recovery
 	 */
-	unlink(RECOVERY_COMMAND_DONE);
-	if (rename(RECOVERY_COMMAND_FILE, RECOVERY_COMMAND_DONE) != 0)
+	if (unlink(RECOVERY_ENABLE_FILE) != 0)
 		ereport(FATAL,
 				(errcode_for_file_access(),
-				 errmsg("could not rename file \"%s\" to \"%s\": %m",
-						RECOVERY_COMMAND_FILE, RECOVERY_COMMAND_DONE)));
+				 errmsg("could not remove file \"%s\": %m",
+						RECOVERY_ENABLE_FILE)));
 
 	ereport(LOG,
 			(errmsg("archive recovery complete")));
@@ -5044,7 +4855,7 @@ recoveryStopsBefore(XLogReaderState *record)
 	TransactionId recordXid;
 
 	/* Check if we should stop as soon as reaching consistency */
-	if (recoveryTarget == RECOVERY_TARGET_IMMEDIATE && reachedConsistency)
+	if (recovery_target == RECOVERY_TARGET_IMMEDIATE && reachedConsistency)
 	{
 		ereport(LOG,
 				(errmsg("recovery stopping after reaching consistency")));
@@ -5084,7 +4895,7 @@ recoveryStopsBefore(XLogReaderState *record)
 	else
 		return false;
 
-	if (recoveryTarget == RECOVERY_TARGET_XID && !recoveryTargetInclusive)
+	if (recovery_target == RECOVERY_TARGET_XID && !recovery_target_inclusive)
 	{
 		/*
 		 * There can be only one transaction end record with this exact
@@ -5095,10 +4906,10 @@ recoveryStopsBefore(XLogReaderState *record)
 		 * they complete. A higher numbered xid will complete before you about
 		 * 50% of the time...
 		 */
-		stopsHere = (recordXid == recoveryTargetXid);
+		stopsHere = (recordXid == recovery_target_xid);
 	}
 
-	if (recoveryTarget == RECOVERY_TARGET_TIME &&
+	if (recovery_target == RECOVERY_TARGET_TIME &&
 		getRecordTimestamp(record, &recordXtime))
 	{
 		/*
@@ -5106,10 +4917,10 @@ recoveryStopsBefore(XLogReaderState *record)
 		 * 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);
+		if (recovery_target_inclusive)
+			stopsHere = (recordXtime > recovery_target_time);
 		else
-			stopsHere = (recordXtime >= recoveryTargetTime);
+			stopsHere = (recordXtime >= recovery_target_time);
 	}
 
 	if (stopsHere)
@@ -5158,14 +4969,14 @@ recoveryStopsAfter(XLogReaderState *record)
 	 * There can be many restore points that share the same name; we stop at
 	 * the first one.
 	 */
-	if (recoveryTarget == RECOVERY_TARGET_NAME &&
+	if (recovery_target == RECOVERY_TARGET_NAME &&
 		rmid == RM_XLOG_ID && record_info == XLOG_RESTORE_POINT)
 	{
 		xl_restore_point *recordRestorePointData;
 
 		recordRestorePointData = (xl_restore_point *) XLogRecGetData(record);
 
-		if (strcmp(recordRestorePointData->rp_name, recoveryTargetName) == 0)
+		if (strcmp(recordRestorePointData->rp_name, recovery_target_name) == 0)
 		{
 			recoveryStopAfter = true;
 			recoveryStopXid = InvalidTransactionId;
@@ -5210,8 +5021,8 @@ recoveryStopsAfter(XLogReaderState *record)
 		 * they complete. A higher numbered xid will complete before you about
 		 * 50% of the time...
 		 */
-		if (recoveryTarget == RECOVERY_TARGET_XID && recoveryTargetInclusive &&
-			recordXid == recoveryTargetXid)
+		if (recovery_target == RECOVERY_TARGET_XID && recovery_target_inclusive &&
+			recordXid == recovery_target_xid)
 		{
 			recoveryStopAfter = true;
 			recoveryStopXid = recordXid;
@@ -5240,7 +5051,7 @@ recoveryStopsAfter(XLogReaderState *record)
 	}
 
 	/* Check if we should stop as soon as reaching consistency */
-	if (recoveryTarget == RECOVERY_TARGET_IMMEDIATE && reachedConsistency)
+	if (recovery_target == RECOVERY_TARGET_IMMEDIATE && reachedConsistency)
 	{
 		ereport(LOG,
 				(errmsg("recovery stopping after reaching consistency")));
@@ -5524,6 +5335,16 @@ CheckRequiredParameterValues(void)
 	}
 }
 
+static void
+InitRecoveryTarget(RecoveryTargetType new_value)
+{
+	if (recovery_target != RECOVERY_TARGET_UNSET)
+		ereport(FATAL,
+				(errmsg("At most one of recovery_target, recovery_target_name, recovery_target_time or recovery_target_xid may be specified.")));
+
+	recovery_target = new_value;
+}
+
 /*
  * This must be called ONCE during postmaster or standalone-backend startup
  */
@@ -5629,37 +5450,45 @@ StartupXLOG(void)
 		recoveryTargetTLI = ControlFile->checkPointCopy.ThisTimeLineID;
 
 	/*
-	 * Check for recovery control file, and if so set up state for offline
-	 * recovery
+	 * Set recovery_target, make sure only one of the recovery_target* GUCs is
+	 * used.
 	 */
-	readRecoveryCommandFile();
+	if (recovery_target_xid_string != NULL)
+		InitRecoveryTarget(RECOVERY_TARGET_XID);
+
+	if (recovery_target_time_string != NULL)
+		InitRecoveryTarget(RECOVERY_TARGET_TIME);
+
+	if (recovery_target_name != NULL)
+		InitRecoveryTarget(RECOVERY_TARGET_NAME);
+
+	if (recovery_target_string != NULL)
+		InitRecoveryTarget(RECOVERY_TARGET_IMMEDIATE);
 
 	/*
-	 * Save archive_cleanup_command in shared memory so that other processes
-	 * can see it.
-	 */
-	strlcpy(XLogCtl->archiveCleanupCommand,
-			archiveCleanupCommand ? archiveCleanupCommand : "",
-			sizeof(XLogCtl->archiveCleanupCommand));
+	 * Check for recovery trigger file, and if so set up state for offline
+	 * recovery.
+ 	 */
+	CheckStartingAsStandby();
 
 	if (ArchiveRecoveryRequested)
 	{
 		if (StandbyModeRequested)
 			ereport(LOG,
 					(errmsg("entering standby mode")));
-		else if (recoveryTarget == RECOVERY_TARGET_XID)
+		else if (recovery_target == RECOVERY_TARGET_XID)
 			ereport(LOG,
 					(errmsg("starting point-in-time recovery to XID %u",
-							recoveryTargetXid)));
-		else if (recoveryTarget == RECOVERY_TARGET_TIME)
+							recovery_target_xid)));
+		else if (recovery_target == RECOVERY_TARGET_TIME)
 			ereport(LOG,
 					(errmsg("starting point-in-time recovery to %s",
-							timestamptz_to_str(recoveryTargetTime))));
-		else if (recoveryTarget == RECOVERY_TARGET_NAME)
+							timestamptz_to_str(recovery_target_time))));
+		else if (recovery_target == RECOVERY_TARGET_NAME)
 			ereport(LOG,
 					(errmsg("starting point-in-time recovery to \"%s\"",
-							recoveryTargetName)));
-		else if (recoveryTarget == RECOVERY_TARGET_IMMEDIATE)
+							recovery_target_name)));
+		else if (recovery_target == RECOVERY_TARGET_IMMEDIATE)
 			ereport(LOG,
 					(errmsg("starting point-in-time recovery to earliest consistent point")));
 		else
@@ -5942,7 +5771,7 @@ 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,
+	 * have been a clean shutdown and we did not have a standby.enabled file,
 	 * then assume no recovery needed.
 	 */
 	if (checkPoint.redo < RecPtr)
@@ -5956,7 +5785,7 @@ StartupXLOG(void)
 		InRecovery = true;
 	else if (ArchiveRecoveryRequested)
 	{
-		/* force recovery due to presence of recovery.conf */
+		/* force recovery due to presence of standby.enabled */
 		InRecovery = true;
 	}
 
@@ -6415,7 +6244,7 @@ StartupXLOG(void)
 			 * end of main redo apply loop
 			 */
 
-			if (recoveryPauseAtTarget && reachedStopPoint)
+			if (pause_at_recovery_target && reachedStopPoint)
 			{
 				SetRecoveryPause(true);
 				recoveryPausesHere();
@@ -6557,21 +6386,21 @@ StartupXLOG(void)
 		 * Create a comment for the history file to explain why and where
 		 * timeline changed.
 		 */
-		if (recoveryTarget == RECOVERY_TARGET_XID)
+		if (recovery_target == RECOVERY_TARGET_XID)
 			snprintf(reason, sizeof(reason),
 					 "%s transaction %u",
 					 recoveryStopAfter ? "after" : "before",
 					 recoveryStopXid);
-		else if (recoveryTarget == RECOVERY_TARGET_TIME)
+		else if (recovery_target == RECOVERY_TARGET_TIME)
 			snprintf(reason, sizeof(reason),
 					 "%s %s\n",
 					 recoveryStopAfter ? "after" : "before",
 					 timestamptz_to_str(recoveryStopTime));
-		else if (recoveryTarget == RECOVERY_TARGET_NAME)
+		else if (recovery_target == RECOVERY_TARGET_NAME)
 			snprintf(reason, sizeof(reason),
 					 "at restore point \"%s\"",
 					 recoveryStopName);
-		else if (recoveryTarget == RECOVERY_TARGET_IMMEDIATE)
+		else if (recovery_target == RECOVERY_TARGET_IMMEDIATE)
 			snprintf(reason, sizeof(reason), "reached consistency");
 		else
 			snprintf(reason, sizeof(reason), "no recovery target specified");
@@ -6719,8 +6548,8 @@ StartupXLOG(void)
 		/*
 		 * And finally, execute the recovery_end_command, if any.
 		 */
-		if (recoveryEndCommand)
-			ExecuteRecoveryCommand(recoveryEndCommand,
+		if (recovery_end_command)
+			ExecuteRecoveryCommand(recovery_end_command,
 								   "recovery_end_command",
 								   true);
 	}
@@ -8248,8 +8077,8 @@ CreateRestartPoint(int flags)
 	/*
 	 * Finally, execute archive_cleanup_command, if any.
 	 */
-	if (XLogCtl->archiveCleanupCommand[0])
-		ExecuteRecoveryCommand(XLogCtl->archiveCleanupCommand,
+	if (archive_cleanup_command)
+		ExecuteRecoveryCommand(archive_cleanup_command,
 							   "archive_cleanup_command",
 							   false);
 
@@ -10244,7 +10073,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 					 * that when we later jump backwards to start redo at
 					 * RedoStartLSN, we will have the logs streamed already.
 					 */
-					if (PrimaryConnInfo)
+					if (primary_conninfo)
 					{
 						XLogRecPtr	ptr;
 						TimeLineID	tli;
@@ -10265,8 +10094,8 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 									 tli, curFileTLI);
 						}
 						curFileTLI = tli;
-						RequestXLogStreaming(tli, ptr, PrimaryConnInfo,
-											 PrimarySlotName);
+						RequestXLogStreaming(tli, ptr, primary_conninfo,
+											 primary_slot_name);
 						receivedUpto = 0;
 					}
 
@@ -10583,14 +10412,14 @@ CheckForStandbyTrigger(void)
 		return true;
 	}
 
-	if (TriggerFile == NULL)
+	if (trigger_file == NULL)
 		return false;
 
-	if (stat(TriggerFile, &stat_buf) == 0)
+	if (stat(trigger_file, &stat_buf) == 0)
 	{
 		ereport(LOG,
-				(errmsg("trigger file found: %s", TriggerFile)));
-		unlink(TriggerFile);
+				(errmsg("trigger file found: %s", trigger_file)));
+		unlink(trigger_file);
 		triggered = true;
 		fast_promote = true;
 		return true;
@@ -10599,7 +10428,7 @@ CheckForStandbyTrigger(void)
 		ereport(ERROR,
 				(errcode_for_file_access(),
 				 errmsg("could not stat trigger file \"%s\": %m",
-						TriggerFile)));
+						trigger_file)));
 
 	return false;
 }
diff --git a/src/backend/access/transam/xlogarchive.c b/src/backend/access/transam/xlogarchive.c
index 047efa2..46e5945 100644
--- a/src/backend/access/transam/xlogarchive.c
+++ b/src/backend/access/transam/xlogarchive.c
@@ -67,7 +67,7 @@ RestoreArchivedFile(char *path, const char *xlogfname,
 	TimeLineID	restartTli;
 
 	/* In standby mode, restore_command might not be supplied */
-	if (recoveryRestoreCommand == NULL)
+	if (restore_command == NULL)
 		goto not_available;
 
 	/*
@@ -150,7 +150,7 @@ RestoreArchivedFile(char *path, const char *xlogfname,
 	endp = xlogRestoreCmd + MAXPGPATH - 1;
 	*endp = '\0';
 
-	for (sp = recoveryRestoreCommand; *sp; sp++)
+	for (sp = restore_command; *sp; sp++)
 	{
 		if (*sp == '%')
 		{
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 9a0afa4..0ed51dd 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -9,7 +9,7 @@
  * 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
+ * postgresql.conf.  An extension also has an installation
  * script file, containing SQL commands to create the extension's objects.
  *
  * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 23cbe90..6d7d306 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -190,6 +190,14 @@ static void assign_application_name(const char *newval, void *extra);
 static bool check_cluster_name(char **newval, void **extra, GucSource source);
 static const char *show_unix_socket_permissions(void);
 static const char *show_log_file_mode(void);
+static bool check_recovery_target(char **newval, void **extra, GucSource source);
+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 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,
@@ -585,6 +593,10 @@ const char *const config_group_names[] =
 	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 */
@@ -1448,6 +1460,36 @@ static struct config_bool ConfigureNamesBool[] =
 	},
 
 	{
+		{"recovery_target_inclusive", PGC_POSTMASTER, 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_POSTMASTER, 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
+		},
+		&StandbyModeRequested,
+		false,
+		NULL, NULL, NULL
+	},
+
+	{
 		{"hot_standby", PGC_POSTMASTER, REPLICATION_STANDBY,
 			gettext_noop("Allows connections and queries during recovery."),
 			NULL
@@ -2714,6 +2756,107 @@ static struct config_string ConfigureNamesString[] =
 	},
 
 	{
+		{"restore_command", PGC_POSTMASTER, 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_POSTMASTER, WAL_ARCHIVE_RECOVERY,
+			gettext_noop("Sets an optional shell command to execute at every restartpoint (can be useful to clean up the archive of a standby server)."),
+			NULL
+		},
+		&archive_cleanup_command,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
+		{"recovery_end_command", PGC_POSTMASTER, 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", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets the recovery 'target' (currently, the only supported value is 'immediate')."),
+			NULL
+		},
+		&recovery_target_string,
+		NULL,
+		check_recovery_target, NULL, NULL
+	},
+
+	{
+		{"recovery_target_xid", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets the transaction ID up to which recovery will proceed."),
+			NULL
+		},
+		&recovery_target_xid_string,
+		NULL,
+		check_recovery_target_xid, assign_recovery_target_xid, NULL
+	},
+
+	{
+		{"recovery_target_name", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets the named restore point."),
+			NULL
+		},
+		&recovery_target_name,
+		NULL,
+		check_recovery_target_name, NULL, NULL
+	},
+
+	{
+		{"recovery_target_time", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets the time stamp up to which recovery will proceed."),
+			NULL
+		},
+		&recovery_target_time_string,
+		NULL,
+		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_POSTMASTER, REPLICATION_STANDBY,
+			gettext_noop("Sets the connection string to be used to connect with the primary."),
+			NULL,
+			GUC_SUPERUSER_ONLY
+		},
+		&primary_conninfo,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
+		{"trigger_file", PGC_POSTMASTER, 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,
@@ -9560,4 +9703,151 @@ show_log_file_mode(void)
 	return buf;
 }
 
+static bool
+check_recovery_target(char **newval, void **extra, GucSource source)
+{
+	if (*newval != NULL && strcmp(*newval, "immediate") != 0) /* strcasecmp? */
+	{
+		GUC_check_errdetail("the only supported value is 'immediate'");
+		return false;
+	}
+	return true;
+}
+
+static bool
+check_recovery_target_xid(char **newval, void **extra, GucSource source)
+{
+	TransactionId   xid;
+	TransactionId   *myextra;
+	char			*endptr;
+
+	if (*newval == NULL)
+		return true;
+
+	if ((*newval)[0] == 0)
+		xid = InvalidTransactionId;
+	else
+	{
+		errno = 0;
+		xid = (TransactionId) strtoul(*newval, &endptr, 0);
+		if (*endptr != 0 || errno == EINVAL || errno == ERANGE)
+		{
+			GUC_check_errdetail("positive integer expected");
+			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)
+{
+	if (extra != NULL)
+		recovery_target_xid = *((TransactionId *) extra);
+}
+
+static bool
+check_recovery_target_name(char **newval, void **extra, GucSource source)
+{
+	if (*newval != NULL && strlen(*newval) >= MAXFNAMELEN)
+	{
+		GUC_check_errdetail("value string is too long (maximum %d characters)",
+							MAXFNAMELEN - 1);
+		return false;
+	}
+	return true;
+}
+
+static bool
+check_recovery_target_time(char **newval, void **extra, GucSource source)
+{
+	TimestampTz     time;
+	TimestampTz     *myextra;
+	MemoryContext	cctx = CurrentMemoryContext;
+
+	if (*newval == NULL)
+		return true;
+
+	if ((*newval)[0] == 0)
+		time = 0;
+	else
+	{
+		PG_TRY();
+		{
+			time = DatumGetTimestampTz(DirectFunctionCall3(timestamptz_in,
+												CStringGetDatum(*newval),
+												ObjectIdGetDatum(InvalidOid),
+												Int32GetDatum(-1)));
+		}
+		PG_CATCH();
+		{
+			ErrorData	*errdata;
+
+			MemoryContextSwitchTo(cctx);
+			errdata = CopyErrorData(); /* do we really have to make a copy? */
+
+			GUC_check_errdetail("%s", errdata->message);
+			/* Don't FlushErrorState() here, the hook caller does that. */
+
+			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)
+{
+	if (extra != NULL)
+		recovery_target_time = *((TimestampTz *) extra);
+}
+
+static bool
+check_recovery_target_timeline(char **newval, void **extra, GucSource source)
+{
+	TimeLineID	tli = 0;
+	TimeLineID	*myextra;
+	char		*endptr;
+
+	if (*newval == NULL)
+		return true;
+
+	if ((*newval)[0] == 0 || strcmp(*newval, "latest") == 0)
+		tli = 0;
+	else
+	{
+		errno = 0;
+		tli = (TimeLineID) strtoul(*newval, &endptr, 0);
+		if (*endptr != 0 || errno == EINVAL || errno == ERANGE)
+		{
+			GUC_check_errdetail("positive integer expected");
+			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)
+{
+	if (extra != NULL)
+		recovery_target_timeline = *((TimeLineID *) extra);
+}
+
 #include "guc-file.c"
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 4a89cb7..75b683d 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -212,6 +212,23 @@
 #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 = ''		# e.g. 'daily backup 2011-01-26'
+#recovery_target_time = ''		# e.g. '2004-07-14 22:39:00 EST'
+#recovery_target_timeline = ''		# timeline ID or 'latest'
+					# (change requires restart)
+#recovery_target_inclusive = on
+#pause_at_recovery_target = on		# Pause recovery once target is reached
+
 
 #------------------------------------------------------------------------------
 # REPLICATION
@@ -257,7 +274,22 @@
 #wal_receiver_timeout = 60s		# time that receiver waits for
 					# communication from master
 					# in milliseconds; 0 disables
-
+#
+# FIXME: do we really need this one if we already have hot_standby and trigger_file?
+#
+#standby_mode = off			# "on" starts the server as a standby
+					# (change requires restart)
+#primary_conninfo = ''			# connection string to connect to the
+					# master e.g. 'host=localhost port=5432'
+#primary_slot_name = ''			# replication slot name to use when
+					# connecting to the master server
+					# (has no effect if primary_conninfo
+					# is not set).
+# FIXME: standby_trigger_file ?
+#trigger_file = ''			# trigger file to promote the standby
+#recovery_min_apply_delay = 0		# minimum time the standby will be
+					# delayed from master in milliseconds;
+					# 0 disables
 
 #------------------------------------------------------------------------------
 # QUERY TUNING
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index e7c2939..7fabf45 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -90,9 +90,6 @@ static int	has_xlogendptr = 0;
 static volatile LONG has_xlogendptr = 0;
 #endif
 
-/* Contents of recovery.conf to be generated */
-static PQExpBuffer recoveryconfcontents = NULL;
-
 /* Function headers */
 static void usage(void);
 static void disconnect_and_exit(int code);
@@ -101,7 +98,6 @@ static void progress_report(int tablespacenum, const char *filename, bool force)
 
 static void ReceiveTarFile(PGconn *conn, PGresult *res, int rownum);
 static void ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum);
-static void GenerateRecoveryConf(PGconn *conn);
 static void WriteRecoveryConf(void);
 static void BaseBackup(void);
 
@@ -899,7 +895,7 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 		{
 			/*
 			 * End of chunk. If requested, and this is the base tablespace,
-			 * write recovery.conf into the tarfile. When done, close the file
+			 * write standby.enabled into the tarfile. When done, close the file
 			 * (but not stdout).
 			 *
 			 * Also, write two completely empty blocks at the end of the tar
@@ -912,19 +908,13 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 			if (basetablespace && writerecoveryconf)
 			{
 				char		header[512];
-				int			padding;
 
-				tarCreateHeader(header, "recovery.conf", NULL,
-								recoveryconfcontents->len,
+				tarCreateHeader(header, "standby.enabled", NULL,
+								0,
 								0600, 04000, 02000,
 								time(NULL));
 
-				padding = ((recoveryconfcontents->len + 511) & ~511) - recoveryconfcontents->len;
-
 				WRITE_TAR_DATA(header, sizeof(header));
-				WRITE_TAR_DATA(recoveryconfcontents->data, recoveryconfcontents->len);
-				if (padding)
-					WRITE_TAR_DATA(zerobuf, padding);
 			}
 
 			/* 2 * 512 bytes empty data at end of file */
@@ -968,8 +958,8 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 		if (!writerecoveryconf || !basetablespace)
 		{
 			/*
-			 * When not writing recovery.conf, or when not working on the base
-			 * tablespace, we never have to look for an existing recovery.conf
+			 * When not writing standby.enabled, or when not working on the base
+			 * tablespace, we never have to look for an existing standby.enabled
 			 * file in the stream.
 			 */
 			WRITE_TAR_DATA(copybuf, r);
@@ -977,7 +967,7 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 		else
 		{
 			/*
-			 * Look for a recovery.conf in the existing tar stream. If it's
+			 * Look for a standby.enabled in the existing tar stream. If it's
 			 * there, we must skip it so we can later overwrite it with our
 			 * own version of the file.
 			 *
@@ -1023,12 +1013,12 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 						 * We have the complete header structure in tarhdr,
 						 * look at the file metadata: - the subsequent file
 						 * contents have to be skipped if the filename is
-						 * recovery.conf - find out the size of the file
+						 * standby.enabled - find out the size of the file
 						 * padded to the next multiple of 512
 						 */
 						int			padding;
 
-						skip_file = (strcmp(&tarhdr[0], "recovery.conf") == 0);
+						skip_file = (strcmp(&tarhdr[0], "standby.enabled") == 0);
 
 						sscanf(&tarhdr[124], "%11o", (unsigned int *) &filesz);
 
@@ -1375,175 +1365,14 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 		WriteRecoveryConf();
 }
 
-/*
- * Escape a parameter value so that it can be used as part of a libpq
- * connection string, e.g. in:
- *
- * application_name=<value>
- *
- * The returned string is malloc'd. Return NULL on out-of-memory.
- */
-static char *
-escapeConnectionParameter(const char *src)
-{
-	bool		need_quotes = false;
-	bool		need_escaping = false;
-	const char *p;
-	char	   *dstbuf;
-	char	   *dst;
-
-	/*
-	 * First check if quoting is needed. Any quote (') or backslash (\)
-	 * characters need to be escaped. Parameters are separated by whitespace,
-	 * so any string containing whitespace characters need to be quoted. An
-	 * empty string is represented by ''.
-	 */
-	if (strchr(src, '\'') != NULL || strchr(src, '\\') != NULL)
-		need_escaping = true;
 
-	for (p = src; *p; p++)
-	{
-		if (isspace((unsigned char) *p))
-		{
-			need_quotes = true;
-			break;
-		}
-	}
-
-	if (*src == '\0')
-		return pg_strdup("''");
-
-	if (!need_quotes && !need_escaping)
-		return pg_strdup(src);	/* no quoting or escaping needed */
-
-	/*
-	 * Allocate a buffer large enough for the worst case that all the source
-	 * characters need to be escaped, plus quotes.
-	 */
-	dstbuf = pg_malloc(strlen(src) * 2 + 2 + 1);
-
-	dst = dstbuf;
-	if (need_quotes)
-		*(dst++) = '\'';
-	for (; *src; src++)
-	{
-		if (*src == '\'' || *src == '\\')
-			*(dst++) = '\\';
-		*(dst++) = *src;
-	}
-	if (need_quotes)
-		*(dst++) = '\'';
-	*dst = '\0';
-
-	return dstbuf;
-}
-
-/*
- * Escape a string so that it can be used as a value in a key-value pair
- * a configuration file.
- */
-static char *
-escape_quotes(const char *src)
-{
-	char	   *result = escape_single_quotes_ascii(src);
-
-	if (!result)
-	{
-		fprintf(stderr, _("%s: out of memory\n"), progname);
-		exit(1);
-	}
-	return result;
-}
-
-/*
- * Create a recovery.conf file in memory using a PQExpBuffer
- */
-static void
-GenerateRecoveryConf(PGconn *conn)
-{
-	PQconninfoOption *connOptions;
-	PQconninfoOption *option;
-	PQExpBufferData conninfo_buf;
-	char	   *escaped;
-
-	recoveryconfcontents = createPQExpBuffer();
-	if (!recoveryconfcontents)
-	{
-		fprintf(stderr, _("%s: out of memory\n"), progname);
-		disconnect_and_exit(1);
-	}
-
-	connOptions = PQconninfo(conn);
-	if (connOptions == NULL)
-	{
-		fprintf(stderr, _("%s: out of memory\n"), progname);
-		disconnect_and_exit(1);
-	}
-
-	appendPQExpBufferStr(recoveryconfcontents, "standby_mode = 'on'\n");
-
-	initPQExpBuffer(&conninfo_buf);
-	for (option = connOptions; option && option->keyword; option++)
-	{
-		/*
-		 * Do not emit this setting if: - the setting is "replication",
-		 * "dbname" or "fallback_application_name", since these would be
-		 * overridden by the libpqwalreceiver module anyway. - not set or
-		 * empty.
-		 */
-		if (strcmp(option->keyword, "replication") == 0 ||
-			strcmp(option->keyword, "dbname") == 0 ||
-			strcmp(option->keyword, "fallback_application_name") == 0 ||
-			(option->val == NULL) ||
-			(option->val != NULL && option->val[0] == '\0'))
-			continue;
-
-		/* Separate key-value pairs with spaces */
-		if (conninfo_buf.len != 0)
-			appendPQExpBufferStr(&conninfo_buf, " ");
-
-		/*
-		 * Write "keyword=value" pieces, the value string is escaped and/or
-		 * quoted if necessary.
-		 */
-		escaped = escapeConnectionParameter(option->val);
-		appendPQExpBuffer(&conninfo_buf, "%s=%s", option->keyword, escaped);
-		free(escaped);
-	}
-
-	/*
-	 * Escape the connection string, so that it can be put in the config file.
-	 * Note that this is different from the escaping of individual connection
-	 * options above!
-	 */
-	escaped = escape_quotes(conninfo_buf.data);
-	appendPQExpBuffer(recoveryconfcontents, "primary_conninfo = '%s'\n", escaped);
-	free(escaped);
-
-	if (PQExpBufferBroken(recoveryconfcontents) ||
-		PQExpBufferDataBroken(conninfo_buf))
-	{
-		fprintf(stderr, _("%s: out of memory\n"), progname);
-		disconnect_and_exit(1);
-	}
-
-	termPQExpBuffer(&conninfo_buf);
-
-	PQconninfoFree(connOptions);
-}
-
-
-/*
- * Write a recovery.conf file into the directory specified in basedir,
- * with the contents already collected in memory.
- */
 static void
 WriteRecoveryConf(void)
 {
 	char		filename[MAXPGPATH];
 	FILE	   *cf;
 
-	sprintf(filename, "%s/recovery.conf", basedir);
+	sprintf(filename, "%s/standby.enabled", basedir);
 
 	cf = fopen(filename, "w");
 	if (cf == NULL)
@@ -1552,14 +1381,6 @@ WriteRecoveryConf(void)
 		disconnect_and_exit(1);
 	}
 
-	if (fwrite(recoveryconfcontents->data, recoveryconfcontents->len, 1, cf) != 1)
-	{
-		fprintf(stderr,
-				_("%s: could not write to file \"%s\": %s\n"),
-				progname, filename, strerror(errno));
-		disconnect_and_exit(1);
-	}
-
 	fclose(cf);
 }
 
@@ -1616,12 +1437,6 @@ BaseBackup(void)
 	}
 
 	/*
-	 * Build contents of recovery.conf if requested
-	 */
-	if (writerecoveryconf)
-		GenerateRecoveryConf(conn);
-
-	/*
 	 * Run IDENTIFY_SYSTEM so we can get the timeline
 	 */
 	if (!RunIdentifySystem(conn, &sysidentifier, &latesttli, NULL, NULL))
@@ -1892,9 +1707,6 @@ BaseBackup(void)
 #endif
 	}
 
-	/* Free the recovery.conf contents */
-	destroyPQExpBuffer(recoveryconfcontents);
-
 	/*
 	 * End of copy data. Final result is already checked inside the loop.
 	 */
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index 733f1cb..fc44586 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -956,7 +956,7 @@ 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
+		 * standby.enabled is also present, we're recovering from an online
 		 * backup instead of performing one.
 		 */
 		if (shutdown_mode == SMART_MODE &&
@@ -1044,7 +1044,7 @@ 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
+		 * standby.enabled is also present, we're recovering from an online
 		 * backup instead of performing one.
 		 */
 		if (shutdown_mode == SMART_MODE &&
@@ -1155,7 +1155,7 @@ do_promote(void)
 		exit(1);
 	}
 
-	/* If recovery.conf doesn't exist, the server is not in standby mode */
+	/* If standby.enabled doesn't exist, the server is not in standby mode */
 	if (stat(recovery_file, &statbuf) != 0)
 	{
 		write_stderr(_("%s: cannot promote server; "
@@ -2371,7 +2371,7 @@ main(int argc, char **argv)
 		snprintf(version_file, MAXPGPATH, "%s/PG_VERSION", 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(recovery_file, MAXPGPATH, "%s/standby.enabled", pg_data);
 	}
 
 	switch (ctl_command)
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index d06fbc0..d8fabe0 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -99,6 +99,23 @@ extern bool EnableHotStandby;
 extern bool fullPageWrites;
 extern bool wal_log_hints;
 extern bool log_checkpoints;
+extern char *restore_command;
+extern char *archive_cleanup_command;
+extern char *recovery_end_command;
+extern bool	StandbyModeRequested;
+extern char *primary_conninfo;
+extern char *trigger_file;
+extern char *recovery_target_string;
+extern RecoveryTargetType recovery_target;
+extern char *recovery_target_xid_string;
+extern TransactionId recovery_target_xid;
+extern char *recovery_target_time_string;
+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
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index 47ff880..a9a231e 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -68,6 +68,8 @@ enum config_group
 	WAL_SETTINGS,
 	WAL_CHECKPOINTS,
 	WAL_ARCHIVING,
+	WAL_ARCHIVE_RECOVERY,
+	WAL_RECOVERY_TARGET,
 	REPLICATION,
 	REPLICATION_SENDING,
 	REPLICATION_MASTER,
diff --git a/src/port/quotes.c b/src/port/quotes.c
index 7c8d4ed..3bc23a6 100644
--- a/src/port/quotes.c
+++ b/src/port/quotes.c
@@ -18,8 +18,7 @@
 /*
  * Escape (by doubling) any single quotes or backslashes in given string
  *
- * Note: this is used to process postgresql.conf entries and to quote
- * string literals in pg_basebackup for creating recovery.conf.
+ * Note: this is used to process postgresql.conf entries
  * Since postgresql.conf strings are defined to treat backslashes as escapes,
  * we have to double backslashes here.
  *
-- 
2.1.0

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to