On Wed, Mar 2, 2016 at 6:49 PM, Marco Nenciarini < marco.nenciar...@2ndquadrant.it> wrote:
> Hi Magnus, > Hi! First, again my apologies for completely missing that you had posted this review! > I've finally found some time to take a look to the patch. > > It applies with some fuzziness on master, but the result looks correct. > Unfortunately the OID of the new pg_stop_backup function conflicts with > "pg_blocking_pids()" patch (52f5d578d6c29bf254e93c69043b817d4047ca67). > Fixed, thanks! > After changing it the patch does not compile: > It compiles fine for me, and with no warnings. > > gcc -Wall -Wmissing-prototypes -Wpointer-arith > -Wdeclaration-after-statement -Wendif-labels -Wmissing-format-attribute > -Wformat-security -fno-strict-aliasing -fwrapv > -Wno-unused-command-line-argument -g -O0 -g -fno-omit-frame-pointer > -I../../../../src/include > > -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/include/libxml2 > -I/usr/local/include -I/usr/local/opt/openssl/include -c -o xlog.o > xlog.c -MMD -MP -MF .deps/xlog.Po > xlog.c:10000:19: error: use of undeclared identifier 'tblspc_mapfbuf'; > Eh. There is no presence of "tblspc_mapfbuf" after the patch. I think it looks like the "applies with fuzziness" actually wasn't correct, and you ended up with bad code with a mix of the old and the new code in it. I've attached an updated patch, which is rebased on current master and includes the oid fix. -- 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 ae93e69..cb1ea71 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -17479,7 +17479,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> @@ -17489,7 +17489,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> diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index b119a47..8634cae 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -9754,8 +9754,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); @@ -9769,8 +9769,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(); @@ -9967,7 +9965,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); @@ -10040,7 +10039,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 @@ -10059,23 +10058,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. @@ -10109,7 +10109,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) || @@ -10118,10 +10118,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) { @@ -10145,7 +10147,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) || @@ -10156,13 +10158,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)); @@ -10269,7 +10267,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..dcf5692 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_backup2 (overloaded as pg_stop_backup in SQL) is called to + * stop non-exclusive backups. */ Datum pg_stop_backup(PG_FUNCTION_ARGS) @@ -97,11 +153,125 @@ 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_backup2: 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_backup2(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')?"))); + + 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')?"))); + + 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; + } + + 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 74a1394..0725827 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -274,8 +274,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..ff20ab7 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_backup2(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 a595327..6b01234 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_backup2 _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