Hi,

Since an exclusive backup method was dropped in v15, in v15 or later, we need to create 
backup_label and tablespace_map files from the result of pg_backup_stop() when taking a base backup 
using low level backup API. One issue when doing this is that; there is no simple way to create 
those files from two columns "labelfile" and "spcmapfile" that pg_backup_stop() 
returns if we execute it via psql. Probaby we need to store those columns in a temporary file and 
run some OS commands or script to separate that file into backup_label and tablespace_map. This is 
not simple way, and which would prevent users from migrating their backup scripts using psql from 
an exclusive backup method to non-exclusive one, I'm afraid.

To enable us to do that more easily, how about adding the pg_backup_label() 
function that returns backup_label and tablespace_map? I'm thinking to make 
this function available just after pg_backup_start() finishes, also even after 
pg_backup_stop() finishes. For example, this function allows us to take a 
backup using the following psql script file.

------------------------------
SELECT * FROM pg_backup_start('test');
\! cp -a $PGDATA /backup
SELECT * FROM pg_backup_stop();

\pset tuples_only on
\pset format unaligned

\o /backup/data/backup_label
SELECT labelfile FROM pg_backup_label();

\o /backup/data/tablespace_map
SELECT spcmapfile FROM pg_backup_label();
------------------------------

Attached is the WIP patch to add pg_backup_label function. No tests nor docs 
have been added yet, but if we can successfully reach the consensus for adding 
the function, I will update the patch.

Thought?

Regards,

--
Fujii Masao
Advanced Computing Technology Center
Research and Development Headquarters
NTT DATA CORPORATION
diff --git a/src/backend/access/transam/xlogfuncs.c 
b/src/backend/access/transam/xlogfuncs.c
index 02bd919ff6..946b119e41 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -41,8 +41,8 @@
 /*
  * Store label file and tablespace map during backups.
  */
-static StringInfo label_file;
-static StringInfo tblspc_map_file;
+static StringInfo label_file = NULL;
+static StringInfo tblspc_map_file = NULL;
 
 /*
  * pg_backup_start: set up for taking an on-line backup dump
@@ -77,10 +77,18 @@ pg_backup_start(PG_FUNCTION_ARGS)
         * Label file and tablespace map file need to be long-lived, since they
         * are read in pg_backup_stop.
         */
-       oldcontext = MemoryContextSwitchTo(TopMemoryContext);
-       label_file = makeStringInfo();
-       tblspc_map_file = makeStringInfo();
-       MemoryContextSwitchTo(oldcontext);
+       if (label_file == NULL)
+       {
+               oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+               label_file = makeStringInfo();
+               tblspc_map_file = makeStringInfo();
+               MemoryContextSwitchTo(oldcontext);
+       }
+       else
+       {
+               resetStringInfo(label_file);
+               resetStringInfo(tblspc_map_file);
+       }
 
        register_persistent_abort_backup_handler();
 
@@ -136,13 +144,36 @@ pg_backup_stop(PG_FUNCTION_ARGS)
        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;
+       /* Returns the record as Datum */
+       PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, 
nulls)));
+}
+
+/*
+ * pg_backup_label: return backup_label and tablespace_map
+ */
+Datum
+pg_backup_label(PG_FUNCTION_ARGS)
+{
+       TupleDesc       tupdesc;
+       Datum           values[2];
+       bool            nulls[2];
+
+       /* Initialize attributes information in the tuple descriptor */
+       if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+               elog(ERROR, "return type must be a row type");
+
+       MemSet(values, 0, sizeof(values));
+       MemSet(nulls, 0, sizeof(nulls));
+
+       if (label_file != NULL)
+               values[0] = CStringGetTextDatum(label_file->data);
+       else
+               nulls[0] = true;
+
+       if (tblspc_map_file != NULL)
+               values[1] = CStringGetTextDatum(tblspc_map_file->data);
+       else
+               nulls[1] = true;
 
        /* Returns the record as Datum */
        PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, 
nulls)));
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 2e41f4d9e8..2f9b0b65f1 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6300,6 +6300,12 @@
   proallargtypes => '{bool,pg_lsn,text,text}', proargmodes => '{i,o,o,o}',
   proargnames => '{wait_for_archive,lsn,labelfile,spcmapfile}',
   prosrc => 'pg_backup_stop' },
+{ oid => '2173', descr => 'return backup label and tablespace map',
+  proname => 'pg_backup_label', provolatile => 'v', proparallel => 'r',
+  prorettype => 'record', proargtypes => '',
+  proallargtypes => '{text,text}', proargmodes => '{o,o}',
+  proargnames => '{labelfile,spcmapfile}',
+  prosrc => 'pg_backup_label' },
 { oid => '3436', descr => 'promote standby server',
   proname => 'pg_promote', provolatile => 'v', prorettype => 'bool',
   proargtypes => 'bool int4', proargnames => '{wait,wait_seconds}',

Reply via email to