On Mon, Apr 4, 2016 at 3:15 PM, Amit Kapila <amit.kapil...@gmail.com> wrote:

> On Mon, Apr 4, 2016 at 4:31 PM, Magnus Hagander <mag...@hagander.net>
> wrote:
>
>> On Fri, Apr 1, 2016 at 6:47 AM, Amit Kapila <amit.kapil...@gmail.com>
>> wrote:
>>
>>
>>> Also, I think below part of documentation for pg_start_backup() needs to
>>> be modified:
>>>
>>> <para>
>>>
>>>     <function>pg_start_backup</> accepts an
>>>
>>>     arbitrary user-defined label for the backup.  (Typically this would
>>> be
>>>
>>>     the name under which the backup dump file will be stored.)  The
>>> function
>>>
>>>     writes a backup label file (<filename>backup_label</>) and, if there
>>>
>>>     are any links in the <filename>pg_tblspc/</> directory, a
>>> tablespace map
>>>
>>>     file (<filename>tablespace_map</>) into the database cluster's data
>>>
>>>     directory, performs a checkpoint, and then returns the backup's
>>> starting
>>>
>>>     transaction log location as text.  The user can ignore this result
>>> value,
>>>
>>>     but it is provided in case it is useful.
>>>
>>
>> That one definitely needs to be fixed, as it's part of the reference.
>> Good spot.
>>
>>
>>
>>> Similarly, there is a description for pg_stop_backup which needs to be
>>> modified.
>>>
>>
>> That's the one you're referring to in your first commend above, is it
>> not? Or is there one more that you mean?
>>
>>
> I am referring to below part of docs in func.sgml
>
> <para>
>
>     <function>pg_stop_backup</> removes the label file and, if it exists,
>
>     the <filename>tablespace_map</> file created by
>
>     <function>pg_start_backup</>, and creates a backup history file in
>
>     the transaction log archive area.  The history file includes the label
> given to
>
>     <function>pg_start_backup</>, the starting and ending transaction log
> locations for
>
>     the backup, and the starting and ending times of the backup.  The
> return
>
>     value is the backup's ending transaction log location (which again
>
>     can be ignored).  After recording the ending location, the current
>
>     transaction log insertion
>
>     point is automatically advanced to the next transaction log file, so
> that the
>
>     ending transaction log file can be archived immediately to complete
> the backup.
>
>  </para>
>
>
Ah, gotcha. Clearly I wasn't paying attention properly.

PFA a better one (I think), also with the rename and added comments that
David was asking for.

Barring objections, I will apply this version.

-- 
 Magnus Hagander
 Me: http://www.hagander.net/
 Work: http://www.redpill-linpro.com/
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 1bc9fbc..c6017e6 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -17478,7 +17478,7 @@ SELECT set_config('log_statement_stats', 'off', false);
       </row>
       <row>
        <entry>
-        <literal><function>pg_start_backup(<parameter>label</> <type>text</> <optional>, <parameter>fast</> <type>boolean</> </optional>)</function></literal>
+        <literal><function>pg_start_backup(<parameter>label</> <type>text</> <optional>, <parameter>fast</> <type>boolean</> <optional>, <parameter>exclusive</> <type>boolean</> </optional></optional>)</function></literal>
         </entry>
        <entry><type>pg_lsn</type></entry>
        <entry>Prepare for performing on-line backup (restricted to superusers or replication roles)</entry>
@@ -17488,7 +17488,14 @@ SELECT set_config('log_statement_stats', 'off', false);
         <literal><function>pg_stop_backup()</function></literal>
         </entry>
        <entry><type>pg_lsn</type></entry>
-       <entry>Finish performing on-line backup (restricted to superusers or replication roles)</entry>
+       <entry>Finish performing exclusive on-line backup (restricted to superusers or replication roles)</entry>
+      </row>
+      <row>
+       <entry>
+        <literal><function>pg_stop_backup(<parameter>exclusive</> <type>boolean</>)</function></literal>
+        </entry>
+       <entry><type>setof record</type></entry>
+       <entry>Finish performing exclusive or non-exclusive on-line backup (restricted to superusers or replication roles)</entry>
       </row>
       <row>
        <entry>
@@ -17537,15 +17544,19 @@ SELECT set_config('log_statement_stats', 'off', false);
    </table>
 
    <para>
-    <function>pg_start_backup</> accepts an
-    arbitrary user-defined label for the backup.  (Typically this would be
-    the name under which the backup dump file will be stored.)  The function
-    writes a backup label file (<filename>backup_label</>) and, if there
-    are any links in the <filename>pg_tblspc/</> directory, a tablespace map
-    file (<filename>tablespace_map</>) into the database cluster's data
-    directory, performs a checkpoint, and then returns the backup's starting
-    transaction log location as text.  The user can ignore this result value,
-    but it is provided in case it is useful.
+    <function>pg_start_backup</> accepts an arbitrary user-defined label for
+    the backup.  (Typically this would be the name under which the backup dump
+    file will be stored.) When used in exclusive mode, the function writes a
+    backup label file (<filename>backup_label</>) and, if there are any links
+    in the <filename>pg_tblspc/</> directory, a tablespace map file
+    (<filename>tablespace_map</>) into the database cluster's data directory,
+    performs a checkpoint, and then returns the backup's starting transaction
+    log location as text.  The user can ignore this result value, but it is
+    provided in case it is useful. When used in non-exclusive mode, the
+    contents of these files are instead returned by the
+    <function>pg_stop_backup</> function, and should be written to the backup
+    by the caller.
+
 <programlisting>
 postgres=# select pg_start_backup('label_goes_here');
  pg_start_backup
@@ -17560,10 +17571,17 @@ postgres=# select pg_start_backup('label_goes_here');
    </para>
 
    <para>
-    <function>pg_stop_backup</> removes the label file and, if it exists,
-    the <filename>tablespace_map</> file created by
-    <function>pg_start_backup</>, and creates a backup history file in
-    the transaction log archive area.  The history file includes the label given to
+    In an exclusive backup, <function>pg_stop_backup</> removes the label file
+    and, if it exists, the <filename>tablespace_map</> file created by
+    <function>pg_start_backup</>. In a non-exclusive backup, the contents of
+    the <filename>backup_label</> and <filename>tablespace_map</> are returned
+    in the result of the function, and should be written to files in the
+    backup (and not in the data directory).
+   </para>
+
+   <para>
+    The function also creates a backup history file in the transaction log
+    archive area. The history file includes the label given to
     <function>pg_start_backup</>, the starting and ending transaction log locations for
     the backup, and the starting and ending times of the backup.  The return
     value is the backup's ending transaction log location (which again
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 06cefe2..902331b 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -9768,8 +9768,8 @@ XLogFileNameP(TimeLineID tli, XLogSegNo segno)
  */
 XLogRecPtr
 do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
-				   char **labelfile, DIR *tblspcdir, List **tablespaces,
-				   char **tblspcmapfile, bool infotbssize,
+				   StringInfo labelfile, DIR *tblspcdir, List **tablespaces,
+				   StringInfo tblspcmapfile, bool infotbssize,
 				   bool needtblspcmapfile)
 {
 	bool		exclusive = (labelfile == NULL);
@@ -9783,8 +9783,6 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 	XLogSegNo	_logSegNo;
 	struct stat stat_buf;
 	FILE	   *fp;
-	StringInfoData labelfbuf;
-	StringInfoData tblspc_mapfbuf;
 
 	backup_started_in_recovery = RecoveryInProgress();
 
@@ -9981,7 +9979,8 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 		/*
 		 * Construct tablespace_map file
 		 */
-		initStringInfo(&tblspc_mapfbuf);
+		if (exclusive)
+			tblspcmapfile = makeStringInfo();
 
 		datadirpathlen = strlen(DataDir);
 
@@ -10054,7 +10053,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 			if (tablespaces)
 				*tablespaces = lappend(*tablespaces, ti);
 
-			appendStringInfo(&tblspc_mapfbuf, "%s %s\n", ti->oid, ti->path);
+			appendStringInfo(tblspcmapfile, "%s %s\n", ti->oid, ti->path);
 
 			pfree(buflinkpath.data);
 #else
@@ -10073,23 +10072,24 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 		/*
 		 * Construct backup label file
 		 */
-		initStringInfo(&labelfbuf);
+		if (exclusive)
+			labelfile = makeStringInfo();
 
 		/* Use the log timezone here, not the session timezone */
 		stamp_time = (pg_time_t) time(NULL);
 		pg_strftime(strfbuf, sizeof(strfbuf),
 					"%Y-%m-%d %H:%M:%S %Z",
 					pg_localtime(&stamp_time, log_timezone));
-		appendStringInfo(&labelfbuf, "START WAL LOCATION: %X/%X (file %s)\n",
+		appendStringInfo(labelfile, "START WAL LOCATION: %X/%X (file %s)\n",
 			 (uint32) (startpoint >> 32), (uint32) startpoint, xlogfilename);
-		appendStringInfo(&labelfbuf, "CHECKPOINT LOCATION: %X/%X\n",
+		appendStringInfo(labelfile, "CHECKPOINT LOCATION: %X/%X\n",
 					 (uint32) (checkpointloc >> 32), (uint32) checkpointloc);
-		appendStringInfo(&labelfbuf, "BACKUP METHOD: %s\n",
+		appendStringInfo(labelfile, "BACKUP METHOD: %s\n",
 						 exclusive ? "pg_start_backup" : "streamed");
-		appendStringInfo(&labelfbuf, "BACKUP FROM: %s\n",
+		appendStringInfo(labelfile, "BACKUP FROM: %s\n",
 						 backup_started_in_recovery ? "standby" : "master");
-		appendStringInfo(&labelfbuf, "START TIME: %s\n", strfbuf);
-		appendStringInfo(&labelfbuf, "LABEL: %s\n", backupidstr);
+		appendStringInfo(labelfile, "START TIME: %s\n", strfbuf);
+		appendStringInfo(labelfile, "LABEL: %s\n", backupidstr);
 
 		/*
 		 * Okay, write the file, or return its contents to caller.
@@ -10123,7 +10123,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 						(errcode_for_file_access(),
 						 errmsg("could not create file \"%s\": %m",
 								BACKUP_LABEL_FILE)));
-			if (fwrite(labelfbuf.data, labelfbuf.len, 1, fp) != 1 ||
+			if (fwrite(labelfile->data, labelfile->len, 1, fp) != 1 ||
 				fflush(fp) != 0 ||
 				pg_fsync(fileno(fp)) != 0 ||
 				ferror(fp) ||
@@ -10132,10 +10132,12 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 						(errcode_for_file_access(),
 						 errmsg("could not write file \"%s\": %m",
 								BACKUP_LABEL_FILE)));
-			pfree(labelfbuf.data);
+			/* Allocated locally for exclusive backups, so free separately */
+			pfree(labelfile->data);
+			pfree(labelfile);
 
 			/* Write backup tablespace_map file. */
-			if (tblspc_mapfbuf.len > 0)
+			if (tblspcmapfile->len > 0)
 			{
 				if (stat(TABLESPACE_MAP, &stat_buf) != 0)
 				{
@@ -10159,7 +10161,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 							(errcode_for_file_access(),
 							 errmsg("could not create file \"%s\": %m",
 									TABLESPACE_MAP)));
-				if (fwrite(tblspc_mapfbuf.data, tblspc_mapfbuf.len, 1, fp) != 1 ||
+				if (fwrite(tblspcmapfile->data, tblspcmapfile->len, 1, fp) != 1 ||
 					fflush(fp) != 0 ||
 					pg_fsync(fileno(fp)) != 0 ||
 					ferror(fp) ||
@@ -10170,13 +10172,9 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 									TABLESPACE_MAP)));
 			}
 
-			pfree(tblspc_mapfbuf.data);
-		}
-		else
-		{
-			*labelfile = labelfbuf.data;
-			if (tblspc_mapfbuf.len > 0)
-				*tblspcmapfile = tblspc_mapfbuf.data;
+			/* Allocated locally for exclusive backups, so free separately */
+			pfree(tblspcmapfile->data);
+			pfree(tblspcmapfile);
 		}
 	}
 	PG_END_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
@@ -10283,7 +10281,16 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
 	 */
 	WALInsertLockAcquireExclusive();
 	if (exclusive)
+	{
+		if (!XLogCtl->Insert.exclusiveBackup)
+		{
+			WALInsertLockRelease();
+			ereport(ERROR,
+					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+					 errmsg("exclusive backup not in progress")));
+		}
 		XLogCtl->Insert.exclusiveBackup = false;
+	}
 	else
 	{
 		/*
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 9ec6b2a..6a2fffc 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -28,14 +28,37 @@
 #include "replication/walreceiver.h"
 #include "storage/smgr.h"
 #include "utils/builtins.h"
+#include "utils/memutils.h"
 #include "utils/numeric.h"
 #include "utils/guc.h"
 #include "utils/pg_lsn.h"
 #include "utils/timestamp.h"
+#include "utils/tuplestore.h"
 #include "storage/fd.h"
+#include "storage/ipc.h"
 
 
 /*
+ * Store label file and tablespace map during non-exclusive backups.
+ */
+static StringInfo label_file;
+static StringInfo tblspc_map_file;
+static bool exclusive_backup_running = false;
+static bool nonexclusive_backup_running = false;
+
+/*
+ * Called when the backend exits with a running non-exclusive base backup,
+ * to clean up state.
+ */
+static void
+nonexclusive_base_backup_cleanup(int code, Datum arg)
+{
+	do_pg_abort_backup();
+	ereport(WARNING,
+			(errmsg("aborting backup due to backend exiting before pg_stop_backup was called")));
+}
+
+/*
  * pg_start_backup: set up for taking an on-line backup dump
  *
  * Essentially what this does is to create a backup label file in $PGDATA,
@@ -49,6 +72,7 @@ pg_start_backup(PG_FUNCTION_ARGS)
 {
 	text	   *backupid = PG_GETARG_TEXT_P(0);
 	bool		fast = PG_GETARG_BOOL(1);
+	bool		exclusive = PG_GETARG_BOOL(2);
 	char	   *backupidstr;
 	XLogRecPtr	startpoint;
 	DIR		   *dir;
@@ -60,14 +84,42 @@ pg_start_backup(PG_FUNCTION_ARGS)
 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 		   errmsg("must be superuser or replication role to run a backup")));
 
+	if (exclusive_backup_running || nonexclusive_backup_running)
+		ereport(ERROR,
+				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+				 errmsg("a backup is already in progress in this session")));
+
 	/* Make sure we can open the directory with tablespaces in it */
 	dir = AllocateDir("pg_tblspc");
 	if (!dir)
 		ereport(ERROR,
 				(errmsg("could not open directory \"%s\": %m", "pg_tblspc")));
 
-	startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL,
-									dir, NULL, NULL, false, true);
+	if (exclusive)
+	{
+		startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL,
+										dir, NULL, NULL, false, true);
+		exclusive_backup_running = true;
+	}
+	else
+	{
+		MemoryContext oldcontext;
+
+		/*
+		 * Label file and tablespace map file need to be long-lived, since they
+		 * are read in pg_stop_backup.
+		 */
+		oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+		label_file = makeStringInfo();
+		tblspc_map_file = makeStringInfo();
+		MemoryContextSwitchTo(oldcontext);
+
+		startpoint = do_pg_start_backup(backupidstr, fast, NULL, label_file,
+										dir, NULL, tblspc_map_file, false, true);
+		nonexclusive_backup_running = true;
+
+		before_shmem_exit(nonexclusive_base_backup_cleanup, (Datum) 0);
+	}
 
 	FreeDir(dir);
 
@@ -86,6 +138,10 @@ pg_start_backup(PG_FUNCTION_ARGS)
  * record for that and the file is for informational and debug purposes only.
  *
  * Note: different from CancelBackup which just cancels online backup mode.
+ *
+ * Note: this version is only called to stop an exclusive backup. The function
+ *       pg_stop_backup_v2 (overloaded as pg_stop_backup in SQL) is called to
+ *       stop non-exclusive backups.
  */
 Datum
 pg_stop_backup(PG_FUNCTION_ARGS)
@@ -97,11 +153,136 @@ pg_stop_backup(PG_FUNCTION_ARGS)
 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 		 (errmsg("must be superuser or replication role to run a backup"))));
 
+	if (nonexclusive_backup_running)
+		ereport(ERROR,
+				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+				 errmsg("non-exclusive backup in progress"),
+				 errhint("did you mean to use pg_stop_backup('f')?")));
+
+	/*
+	 * Exclusive backups were typically started in a different connection,
+	 * so don't try to verify that exclusive_backup_running is set in this one.
+	 * Actual verification that an exclusive backup is in fact running is handled
+	 * inside do_pg_stop_backup.
+	 */
 	stoppoint = do_pg_stop_backup(NULL, true, NULL);
 
+	exclusive_backup_running = false;
+
 	PG_RETURN_LSN(stoppoint);
 }
 
+
+/*
+ * pg_stop_backup_v2: finish taking exclusive or nonexclusive on-line backup.
+ *
+ * Works the same as pg_stop_backup, except for non-exclusive backups it returns
+ * the backup label and tablespace map files as text fields in as part of the
+ * resultset.
+ */
+Datum
+pg_stop_backup_v2(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo  *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+	TupleDesc		tupdesc;
+	Tuplestorestate *tupstore;
+	MemoryContext	per_query_ctx;
+	MemoryContext	oldcontext;
+	Datum			values[3];
+	bool			nulls[3];
+
+	bool			exclusive = PG_GETARG_BOOL(0);
+	XLogRecPtr		stoppoint;
+
+	/* check to see if caller supports us returning a tuplestore */
+	if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("set-valued function called in context that cannot accept a set")));
+	if (!(rsinfo->allowedModes & SFRM_Materialize))
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("materialize mode required, but it is not " \
+						"allowed in this context")));
+
+	if (!superuser() && !has_rolreplication(GetUserId()))
+		ereport(ERROR,
+				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+				 (errmsg("must be superuser or replication role to run a backup"))));
+
+	/* Build a tuple descriptor for our result type */
+	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+		elog(ERROR, "return type must be a row type");
+
+	per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
+	oldcontext = MemoryContextSwitchTo(per_query_ctx);
+
+	tupstore = tuplestore_begin_heap(true, false, work_mem);
+	rsinfo->returnMode = SFRM_Materialize;
+	rsinfo->setResult = tupstore;
+	rsinfo->setDesc = tupdesc;
+
+	MemoryContextSwitchTo(oldcontext);
+
+	MemSet(values, 0, sizeof(values));
+	MemSet(nulls, 0, sizeof(nulls));
+
+	if (exclusive)
+	{
+		if (nonexclusive_backup_running)
+			ereport(ERROR,
+					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+					 errmsg("non-exclusive backup in progress"),
+					 errhint("did you mean to use pg_stop_backup('f')?")));
+
+		/*
+		 * Stop the exclusive backup, and since we're in an exclusive backup
+		 * return NULL for both backup_label and tablespace_map.
+		 */
+		stoppoint = do_pg_stop_backup(NULL, true, NULL);
+		exclusive_backup_running = false;
+
+		nulls[1] = true;
+		nulls[2] = true;
+	}
+	else
+	{
+		if (!nonexclusive_backup_running)
+			ereport(ERROR,
+					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+					 errmsg("non-exclusive backup is not in progress"),
+					 errhint("did you mean to use pg_stop_backup('t')?")));
+
+		/*
+		 * Stop the non-exclusive backup. Return a copy of the backup
+		 * label and tablespace map so they can be written to disk by
+		 * the caller.
+		 */
+		stoppoint = do_pg_stop_backup(label_file->data, true, NULL);
+		nonexclusive_backup_running = false;
+		cancel_before_shmem_exit(nonexclusive_base_backup_cleanup, (Datum) 0);
+
+		values[1] = CStringGetTextDatum(label_file->data);
+		values[2] = CStringGetTextDatum(tblspc_map_file->data);
+
+		/* Free structures allocated in TopMemoryContext */
+		pfree(label_file->data);
+		pfree(label_file);
+		label_file = NULL;
+		pfree(tblspc_map_file->data);
+		pfree(tblspc_map_file);
+		tblspc_map_file = NULL;
+	}
+
+	/* Stoppoint is included on both exclusive and nonexclusive backups */
+	values[0]  = LSNGetDatum(stoppoint);
+
+	tuplestore_putvalues(tupstore, tupdesc, values, nulls);
+	tuplestore_donestoring(typstore);
+
+	return (Datum) 0;
+}
+
 /*
  * pg_switch_xlog: switch to next xlog file
  */
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 9ae1ef4..2bd40a1 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -921,7 +921,7 @@ COMMENT ON FUNCTION ts_debug(text) IS
 --
 
 CREATE OR REPLACE FUNCTION
-  pg_start_backup(label text, fast boolean DEFAULT false)
+  pg_start_backup(label text, fast boolean DEFAULT false, exclusive boolean DEFAULT true)
   RETURNS pg_lsn STRICT VOLATILE LANGUAGE internal AS 'pg_start_backup';
 
 -- legacy definition for compatibility with 9.3
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index af0fb09..1008873 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -117,8 +117,8 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
 	TimeLineID	starttli;
 	XLogRecPtr	endptr;
 	TimeLineID	endtli;
-	char	   *labelfile;
-	char	   *tblspc_map_file = NULL;
+	StringInfo  labelfile;
+	StringInfo  tblspc_map_file = NULL;
 	int			datadirpathlen;
 	List	   *tablespaces = NIL;
 
@@ -126,9 +126,12 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
 
 	backup_started_in_recovery = RecoveryInProgress();
 
+	labelfile = makeStringInfo();
+	tblspc_map_file = makeStringInfo();
+
 	startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint, &starttli,
-								  &labelfile, tblspcdir, &tablespaces,
-								  &tblspc_map_file,
+								  labelfile, tblspcdir, &tablespaces,
+								  tblspc_map_file,
 								  opt->progress, opt->sendtblspcmapfile);
 
 	/*
@@ -206,7 +209,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
 				struct stat statbuf;
 
 				/* In the main tar, include the backup_label first... */
-				sendFileWithContent(BACKUP_LABEL_FILE, labelfile);
+				sendFileWithContent(BACKUP_LABEL_FILE, labelfile->data);
 
 				/*
 				 * Send tablespace_map file if required and then the bulk of
@@ -214,7 +217,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
 				 */
 				if (tblspc_map_file && opt->sendtblspcmapfile)
 				{
-					sendFileWithContent(TABLESPACE_MAP, tblspc_map_file);
+					sendFileWithContent(TABLESPACE_MAP, tblspc_map_file->data);
 					sendDir(".", 1, false, tablespaces, false);
 				}
 				else
@@ -247,7 +250,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
 	}
 	PG_END_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
 
-	endptr = do_pg_stop_backup(labelfile, !opt->nowait, &endtli);
+	endptr = do_pg_stop_backup(labelfile->data, !opt->nowait, &endtli);
 
 	if (opt->includewal)
 	{
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index a7dcdae..0744c3f 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -276,8 +276,8 @@ extern void assign_checkpoint_completion_target(double newval, void *extra);
  * Starting/stopping a base backup
  */
 extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast,
-				   TimeLineID *starttli_p, char **labelfile, DIR *tblspcdir,
-				   List **tablespaces, char **tblspcmapfile, bool infotbssize,
+				   TimeLineID *starttli_p, StringInfo labelfile, DIR *tblspcdir,
+				   List **tablespaces, StringInfo tblspcmapfile, bool infotbssize,
 				   bool needtblspcmapfile);
 extern XLogRecPtr do_pg_stop_backup(char *labelfile, bool waitforarchive,
 				  TimeLineID *stoptli_p);
diff --git a/src/include/access/xlog_fn.h b/src/include/access/xlog_fn.h
index 762df8b..576a4dc 100644
--- a/src/include/access/xlog_fn.h
+++ b/src/include/access/xlog_fn.h
@@ -15,6 +15,7 @@
 
 extern Datum pg_start_backup(PG_FUNCTION_ARGS);
 extern Datum pg_stop_backup(PG_FUNCTION_ARGS);
+extern Datum pg_stop_backup_v2(PG_FUNCTION_ARGS);
 extern Datum pg_switch_xlog(PG_FUNCTION_ARGS);
 extern Datum pg_create_restore_point(PG_FUNCTION_ARGS);
 extern Datum pg_current_xlog_location(PG_FUNCTION_ARGS);
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index c86b920..c0d88ab 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -3075,10 +3075,12 @@ DATA(insert OID = 2171 ( pg_cancel_backend		PGNSP PGUID 12 1 0 0 0 f f f f t f v
 DESCR("cancel a server process' current query");
 DATA(insert OID = 2096 ( pg_terminate_backend		PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 16 "23" _null_ _null_ _null_ _null_ _null_ pg_terminate_backend _null_ _null_ _null_ ));
 DESCR("terminate a server process");
-DATA(insert OID = 2172 ( pg_start_backup		PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 3220 "25 16" _null_ _null_ _null_ _null_ _null_ pg_start_backup _null_ _null_ _null_ ));
+DATA(insert OID = 2172 ( pg_start_backup		PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 3220 "25 16 16" _null_ _null_ _null_ _null_ _null_ pg_start_backup _null_ _null_ _null_ ));
 DESCR("prepare for taking an online backup");
 DATA(insert OID = 2173 ( pg_stop_backup			PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 3220 "" _null_ _null_ _null_ _null_ _null_ pg_stop_backup _null_ _null_ _null_ ));
 DESCR("finish taking an online backup");
+DATA(insert OID = 2739 ( pg_stop_backup			PGNSP PGUID 12 1 1 0 0 f f f f t t v s 1 0 2249 "16" "{16,3220,25,25}" "{i,o,o,o}" "{exclusive,lsn,labelfile,spcmapfile}" _null_ _null_ pg_stop_backup_v2 _null_ _null_ _null_ ));
+DESCR("finish taking an online backup");
 DATA(insert OID = 3813 ( pg_is_in_backup		PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 16 "" _null_ _null_ _null_ _null_ _null_ pg_is_in_backup _null_ _null_ _null_ ));
 DESCR("true if server is in online backup");
 DATA(insert OID = 3814 ( pg_backup_start_time		PGNSP PGUID 12 1 0 0 0 f f f f t f s s 0 0 1184 "" _null_ _null_ _null_ _null_ _null_ pg_backup_start_time _null_ _null_ _null_ ));
-- 
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