Make pg_dump error cleanly with -j against hot standby

Getting a synchronized snapshot is not supported on a hot standby node,
and is by default taken when using -j with multiple sessions. Trying to
do so still failed, but with a server error that would also go in the
log. Instead, proprely detect this case and give a better error message.
This commit is contained in:
Magnus Hagander 2016-05-26 22:14:23 +02:00
parent aeb9ae6457
commit d74048defc
4 changed files with 53 additions and 40 deletions

View File

@ -173,6 +173,7 @@ typedef struct Archive
int verbose;
char *remoteVersionStr; /* server's version string */
int remoteVersion; /* same in numeric form */
bool isStandby; /* is server a standby node */
int minRemoteVersion; /* allowable range */
int maxRemoteVersion;

View File

@ -37,6 +37,7 @@ _check_database_version(ArchiveHandle *AH)
{
const char *remoteversion_str;
int remoteversion;
PGresult *res;
remoteversion_str = PQparameterStatus(AH->connection, "server_version");
remoteversion = PQserverVersion(AH->connection);
@ -56,6 +57,20 @@ _check_database_version(ArchiveHandle *AH)
remoteversion_str, progname, PG_VERSION);
exit_horribly(NULL, "aborting because of server version mismatch\n");
}
/*
* When running against 9.0 or later, check if we are in recovery mode,
* which means we are on a hot standby.
*/
if (remoteversion >= 90000)
{
res = ExecuteSqlQueryForSingleRow((Archive *) AH, "SELECT pg_catalog.pg_is_in_recovery()");
AH->public.isStandby = (strcmp(PQgetvalue(res, 0, 0), "t") == 0);
PQclear(res);
}
else
AH->public.isStandby = false;
}
/*
@ -388,6 +403,29 @@ ExecuteSqlQuery(Archive *AHX, const char *query, ExecStatusType status)
return res;
}
/*
* Execute an SQL query and verify that we got exactly one row back.
*/
PGresult *
ExecuteSqlQueryForSingleRow(Archive *fout, char *query)
{
PGresult *res;
int ntups;
res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
/* Expecting a single result only */
ntups = PQntuples(res);
if (ntups != 1)
exit_horribly(NULL,
ngettext("query returned %d row instead of one: %s\n",
"query returned %d rows instead of one: %s\n",
ntups),
ntups, query);
return res;
}
/*
* Convenience function to send a query.
* Monitors result to detect COPY statements

View File

@ -16,6 +16,7 @@ extern int ExecuteSqlCommandBuf(Archive *AHX, const char *buf, size_t bufLen);
extern void ExecuteSqlStatement(Archive *AHX, const char *query);
extern PGresult *ExecuteSqlQuery(Archive *AHX, const char *query,
ExecStatusType status);
extern PGresult *ExecuteSqlQueryForSingleRow(Archive *fout, char *query);
extern void EndDBCopyMode(Archive *AHX, const char *tocEntryTag);

View File

@ -264,7 +264,6 @@ static bool nonemptyReloptions(const char *reloptions);
static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
const char *prefix, Archive *fout);
static char *get_synchronized_snapshot(Archive *fout);
static PGresult *ExecuteSqlQueryForSingleRow(Archive *fout, char *query);
static void setupDumpWorker(Archive *AHX);
@ -657,23 +656,11 @@ main(int argc, char **argv)
dopt.no_security_labels = 1;
/*
* When running against 9.0 or later, check if we are in recovery mode,
* which means we are on a hot standby.
* On hot standby slaves, never try to dump unlogged table data, since it
* will just throw an error.
*/
if (fout->remoteVersion >= 90000)
{
PGresult *res = ExecuteSqlQueryForSingleRow(fout, "SELECT pg_catalog.pg_is_in_recovery()");
if (strcmp(PQgetvalue(res, 0, 0), "t") == 0)
{
/*
* On hot standby slaves, never try to dump unlogged table data,
* since it will just throw an error.
*/
dopt.no_unlogged_table_data = true;
}
PQclear(res);
}
if (fout->isStandby)
dopt.no_unlogged_table_data = true;
/* Select the appropriate subquery to convert user IDs to names */
if (fout->remoteVersion >= 80100)
@ -1105,7 +1092,16 @@ setup_connection(Archive *AH, const char *dumpencoding,
else if (AH->numWorkers > 1 &&
AH->remoteVersion >= 90200 &&
!dopt->no_synchronized_snapshots)
{
if (AH->isStandby)
exit_horribly(NULL,
"Synchronized snapshots are not supported on standby servers.\n"
"Run with --no-synchronized-snapshots instead if you do not need\n"
"synchronized snapshots.\n");
AH->sync_snapshot_id = get_synchronized_snapshot(AH);
}
}
static void
@ -17855,26 +17851,3 @@ appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
if (!res)
write_msg(NULL, "WARNING: could not parse reloptions array\n");
}
/*
* Execute an SQL query and verify that we got exactly one row back.
*/
static PGresult *
ExecuteSqlQueryForSingleRow(Archive *fout, char *query)
{
PGresult *res;
int ntups;
res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
/* Expecting a single result only */
ntups = PQntuples(res);
if (ntups != 1)
exit_horribly(NULL,
ngettext("query returned %d row instead of one: %s\n",
"query returned %d rows instead of one: %s\n",
ntups),
ntups, query);
return res;
}