mirror of
https://github.com/postgres/postgres.git
synced 2025-05-02 11:44:50 +03:00
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:
parent
aa86edb38d
commit
47e5969767
@ -172,6 +172,7 @@ typedef struct Archive
|
|||||||
int verbose;
|
int verbose;
|
||||||
char *remoteVersionStr; /* server's version string */
|
char *remoteVersionStr; /* server's version string */
|
||||||
int remoteVersion; /* same in numeric form */
|
int remoteVersion; /* same in numeric form */
|
||||||
|
bool isStandby; /* is server a standby node */
|
||||||
|
|
||||||
int minRemoteVersion; /* allowable range */
|
int minRemoteVersion; /* allowable range */
|
||||||
int maxRemoteVersion;
|
int maxRemoteVersion;
|
||||||
|
@ -37,6 +37,7 @@ _check_database_version(ArchiveHandle *AH)
|
|||||||
{
|
{
|
||||||
const char *remoteversion_str;
|
const char *remoteversion_str;
|
||||||
int remoteversion;
|
int remoteversion;
|
||||||
|
PGresult *res;
|
||||||
|
|
||||||
remoteversion_str = PQparameterStatus(AH->connection, "server_version");
|
remoteversion_str = PQparameterStatus(AH->connection, "server_version");
|
||||||
remoteversion = PQserverVersion(AH->connection);
|
remoteversion = PQserverVersion(AH->connection);
|
||||||
@ -56,6 +57,20 @@ _check_database_version(ArchiveHandle *AH)
|
|||||||
remoteversion_str, progname, PG_VERSION);
|
remoteversion_str, progname, PG_VERSION);
|
||||||
exit_horribly(NULL, "aborting because of server version mismatch\n");
|
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;
|
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.
|
* Convenience function to send a query.
|
||||||
* Monitors result to detect COPY statements
|
* Monitors result to detect COPY statements
|
||||||
|
@ -16,6 +16,7 @@ extern int ExecuteSqlCommandBuf(Archive *AHX, const char *buf, size_t bufLen);
|
|||||||
extern void ExecuteSqlStatement(Archive *AHX, const char *query);
|
extern void ExecuteSqlStatement(Archive *AHX, const char *query);
|
||||||
extern PGresult *ExecuteSqlQuery(Archive *AHX, const char *query,
|
extern PGresult *ExecuteSqlQuery(Archive *AHX, const char *query,
|
||||||
ExecStatusType status);
|
ExecStatusType status);
|
||||||
|
extern PGresult *ExecuteSqlQueryForSingleRow(Archive *fout, char *query);
|
||||||
|
|
||||||
extern void EndDBCopyMode(Archive *AHX, const char *tocEntryTag);
|
extern void EndDBCopyMode(Archive *AHX, const char *tocEntryTag);
|
||||||
|
|
||||||
|
@ -255,7 +255,6 @@ static bool nonemptyReloptions(const char *reloptions);
|
|||||||
static void fmtReloptionsArray(Archive *fout, PQExpBuffer buffer,
|
static void fmtReloptionsArray(Archive *fout, PQExpBuffer buffer,
|
||||||
const char *reloptions, const char *prefix);
|
const char *reloptions, const char *prefix);
|
||||||
static char *get_synchronized_snapshot(Archive *fout);
|
static char *get_synchronized_snapshot(Archive *fout);
|
||||||
static PGresult *ExecuteSqlQueryForSingleRow(Archive *fout, char *query);
|
|
||||||
static void setupDumpWorker(Archive *AHX);
|
static void setupDumpWorker(Archive *AHX);
|
||||||
|
|
||||||
|
|
||||||
@ -647,23 +646,11 @@ main(int argc, char **argv)
|
|||||||
dopt.no_security_labels = 1;
|
dopt.no_security_labels = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When running against 9.0 or later, check if we are in recovery mode,
|
* On hot standby slaves, never try to dump unlogged table data, since it
|
||||||
* which means we are on a hot standby.
|
* will just throw an error.
|
||||||
*/
|
*/
|
||||||
if (fout->remoteVersion >= 90000)
|
if (fout->isStandby)
|
||||||
{
|
dopt.no_unlogged_table_data = true;
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Select the appropriate subquery to convert user IDs to names */
|
/* Select the appropriate subquery to convert user IDs to names */
|
||||||
if (fout->remoteVersion >= 80100)
|
if (fout->remoteVersion >= 80100)
|
||||||
@ -1088,7 +1075,16 @@ setup_connection(Archive *AH, const char *dumpencoding,
|
|||||||
else if (AH->numWorkers > 1 &&
|
else if (AH->numWorkers > 1 &&
|
||||||
AH->remoteVersion >= 90200 &&
|
AH->remoteVersion >= 90200 &&
|
||||||
!dopt->no_synchronized_snapshots)
|
!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);
|
AH->sync_snapshot_id = get_synchronized_snapshot(AH);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -16559,26 +16555,3 @@ fmtReloptionsArray(Archive *fout, PQExpBuffer buffer, const char *reloptions,
|
|||||||
if (options)
|
if (options)
|
||||||
free(options);
|
free(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user