1
0
mirror of https://github.com/postgrespro/pg_probackup.git synced 2024-12-05 11:00:22 +02:00

PGPRO-1290: Check connected server version with build version

This commit is contained in:
Arthur Zakirov 2018-05-16 10:00:49 +03:00
parent c408a0ea47
commit d8005d5496
6 changed files with 84 additions and 37 deletions

View File

@ -934,6 +934,8 @@ do_backup(time_t start_time)
static void static void
check_server_version(void) check_server_version(void)
{ {
PGresult *res;
/* confirm server version */ /* confirm server version */
server_version = PQserverVersion(backup_conn); server_version = PQserverVersion(backup_conn);
@ -958,6 +960,39 @@ check_server_version(void)
"server version is %s, must be %s or higher for backup from replica", "server version is %s, must be %s or higher for backup from replica",
server_version_str, "9.6"); server_version_str, "9.6");
res = pgut_execute_extended(backup_conn, "SELECT pgpro_edition()",
0, NULL, true, true);
/*
* Check major version of connected PostgreSQL and major version of
* compiled PostgreSQL.
*/
#ifdef PGPRO_VERSION
if (PQresultStatus(res) == PGRES_FATAL_ERROR)
/* It seems we connected to PostgreSQL (not Postgres Pro) */
elog(ERROR, "%s was built with Postgres Pro %s %s, "
"but connection made with PostgreSQL %s",
PROGRAM_NAME, PG_MAJORVERSION, PGPRO_EDITION, server_version_str);
else if (strcmp(server_version_str, PG_MAJORVERSION) != 0 &&
strcmp(PQgetvalue(res, 0, 0), PGPRO_EDITION) != 0)
elog(ERROR, "%s was built with Postgres Pro %s %s, "
"but connection made with Postgres Pro %s %s",
PROGRAM_NAME, PG_MAJORVERSION, PGPRO_EDITION,
server_version_str, PQgetvalue(res, 0, 0));
#else
if (PQresultStatus(res) != PGRES_FATAL_ERROR)
/* It seems we connected to Postgres Pro (not PostgreSQL) */
elog(ERROR, "%s was built with PostgreSQL %s, "
"but connection made with Postgres Pro %s %s",
PROGRAM_NAME, PG_MAJORVERSION,
server_version_str, PQgetvalue(res, 0, 0));
else if (strcmp(server_version_str, PG_MAJORVERSION) != 0)
elog(ERROR, "%s was built with PostgreSQL %s, but connection made with %s",
PROGRAM_NAME, PG_MAJORVERSION, server_version_str);
#endif
PQclear(res);
/* Do exclusive backup only for PostgreSQL 9.5 */ /* Do exclusive backup only for PostgreSQL 9.5 */
exclusive_backup = server_version < 90600 || exclusive_backup = server_version < 90600 ||
current.backup_mode == BACKUP_MODE_DIFF_PTRACK; current.backup_mode == BACKUP_MODE_DIFF_PTRACK;
@ -997,7 +1032,7 @@ confirm_block_size(const char *name, int blcksz)
char *endp; char *endp;
int block_size; int block_size;
res = pgut_execute(backup_conn, "SELECT pg_catalog.current_setting($1)", 1, &name, true); res = pgut_execute(backup_conn, "SELECT pg_catalog.current_setting($1)", 1, &name);
if (PQntuples(res) != 1 || PQnfields(res) != 1) if (PQntuples(res) != 1 || PQnfields(res) != 1)
elog(ERROR, "cannot get %s: %s", name, PQerrorMessage(backup_conn)); elog(ERROR, "cannot get %s: %s", name, PQerrorMessage(backup_conn));
@ -1033,14 +1068,12 @@ pg_start_backup(const char *label, bool smooth, pgBackup *backup)
res = pgut_execute(conn, res = pgut_execute(conn,
"SELECT pg_catalog.pg_start_backup($1, $2, false)", "SELECT pg_catalog.pg_start_backup($1, $2, false)",
2, 2,
params, params);
true);
else else
res = pgut_execute(conn, res = pgut_execute(conn,
"SELECT pg_catalog.pg_start_backup($1, $2)", "SELECT pg_catalog.pg_start_backup($1, $2)",
2, 2,
params, params);
true);
/* Extract timeline and LSN from results of pg_start_backup() */ /* Extract timeline and LSN from results of pg_start_backup() */
XLogDataFromLSN(PQgetvalue(res, 0, 0), &xlogid, &xrecoff); XLogDataFromLSN(PQgetvalue(res, 0, 0), &xlogid, &xrecoff);
@ -1091,13 +1124,13 @@ pg_switch_wal(PGconn *conn)
PGresult *res; PGresult *res;
/* Remove annoying NOTICE messages generated by backend */ /* Remove annoying NOTICE messages generated by backend */
res = pgut_execute(conn, "SET client_min_messages = warning;", 0, NULL, true); res = pgut_execute(conn, "SET client_min_messages = warning;", 0, NULL);
PQclear(res); PQclear(res);
if (server_version >= 100000) if (server_version >= 100000)
res = pgut_execute(conn, "SELECT * FROM pg_catalog.pg_switch_wal()", 0, NULL, true); res = pgut_execute(conn, "SELECT * FROM pg_catalog.pg_switch_wal()", 0, NULL);
else else
res = pgut_execute(conn, "SELECT * FROM pg_catalog.pg_switch_xlog()", 0, NULL, true); res = pgut_execute(conn, "SELECT * FROM pg_catalog.pg_switch_xlog()", 0, NULL);
PQclear(res); PQclear(res);
} }
@ -1113,7 +1146,7 @@ pg_ptrack_support(void)
res_db = pgut_execute(backup_conn, res_db = pgut_execute(backup_conn,
"SELECT proname FROM pg_proc WHERE proname='ptrack_version'", "SELECT proname FROM pg_proc WHERE proname='ptrack_version'",
0, NULL, true); 0, NULL);
if (PQntuples(res_db) == 0) if (PQntuples(res_db) == 0)
{ {
PQclear(res_db); PQclear(res_db);
@ -1123,7 +1156,7 @@ pg_ptrack_support(void)
res_db = pgut_execute(backup_conn, res_db = pgut_execute(backup_conn,
"SELECT pg_catalog.ptrack_version()", "SELECT pg_catalog.ptrack_version()",
0, NULL, true); 0, NULL);
if (PQntuples(res_db) == 0) if (PQntuples(res_db) == 0)
{ {
PQclear(res_db); PQclear(res_db);
@ -1148,7 +1181,7 @@ pg_ptrack_enable(void)
{ {
PGresult *res_db; PGresult *res_db;
res_db = pgut_execute(backup_conn, "show ptrack_enable", 0, NULL, true); res_db = pgut_execute(backup_conn, "show ptrack_enable", 0, NULL);
if (strcmp(PQgetvalue(res_db, 0, 0), "on") != 0) if (strcmp(PQgetvalue(res_db, 0, 0), "on") != 0)
{ {
@ -1165,7 +1198,7 @@ pg_checksum_enable(void)
{ {
PGresult *res_db; PGresult *res_db;
res_db = pgut_execute(backup_conn, "show data_checksums", 0, NULL, true); res_db = pgut_execute(backup_conn, "show data_checksums", 0, NULL);
if (strcmp(PQgetvalue(res_db, 0, 0), "on") != 0) if (strcmp(PQgetvalue(res_db, 0, 0), "on") != 0)
{ {
@ -1182,7 +1215,7 @@ pg_is_in_recovery(void)
{ {
PGresult *res_db; PGresult *res_db;
res_db = pgut_execute(backup_conn, "SELECT pg_catalog.pg_is_in_recovery()", 0, NULL, true); res_db = pgut_execute(backup_conn, "SELECT pg_catalog.pg_is_in_recovery()", 0, NULL);
if (PQgetvalue(res_db, 0, 0)[0] == 't') if (PQgetvalue(res_db, 0, 0)[0] == 't')
{ {
@ -1207,7 +1240,7 @@ pg_ptrack_clear(void)
params[0] = palloc(64); params[0] = palloc(64);
params[1] = palloc(64); params[1] = palloc(64);
res_db = pgut_execute(backup_conn, "SELECT datname, oid, dattablespace FROM pg_database", res_db = pgut_execute(backup_conn, "SELECT datname, oid, dattablespace FROM pg_database",
0, NULL, true); 0, NULL);
for(i = 0; i < PQntuples(res_db); i++) for(i = 0; i < PQntuples(res_db); i++)
{ {
@ -1221,12 +1254,12 @@ pg_ptrack_clear(void)
tblspcOid = atoi(PQgetvalue(res_db, i, 2)); tblspcOid = atoi(PQgetvalue(res_db, i, 2));
tmp_conn = pgut_connect(dbname); tmp_conn = pgut_connect(dbname);
res = pgut_execute(tmp_conn, "SELECT pg_catalog.pg_ptrack_clear()", 0, NULL, true); res = pgut_execute(tmp_conn, "SELECT pg_catalog.pg_ptrack_clear()", 0, NULL);
sprintf(params[0], "%i", dbOid); sprintf(params[0], "%i", dbOid);
sprintf(params[1], "%i", tblspcOid); sprintf(params[1], "%i", tblspcOid);
res = pgut_execute(tmp_conn, "SELECT pg_catalog.pg_ptrack_get_and_clear_db($1, $2)", res = pgut_execute(tmp_conn, "SELECT pg_catalog.pg_ptrack_get_and_clear_db($1, $2)",
2, (const char **)params, true); 2, (const char **)params);
PQclear(res); PQclear(res);
pgut_disconnect(tmp_conn); pgut_disconnect(tmp_conn);
@ -1252,7 +1285,7 @@ pg_ptrack_get_and_clear_db(Oid dbOid, Oid tblspcOid)
sprintf(params[0], "%i", dbOid); sprintf(params[0], "%i", dbOid);
res_db = pgut_execute(backup_conn, res_db = pgut_execute(backup_conn,
"SELECT datname FROM pg_database WHERE oid=$1", "SELECT datname FROM pg_database WHERE oid=$1",
1, (const char **) params, true); 1, (const char **) params);
/* /*
* If database is not found, it's not an error. * If database is not found, it's not an error.
* It could have been deleted since previous backup. * It could have been deleted since previous backup.
@ -1273,7 +1306,7 @@ pg_ptrack_get_and_clear_db(Oid dbOid, Oid tblspcOid)
sprintf(params[0], "%i", dbOid); sprintf(params[0], "%i", dbOid);
sprintf(params[1], "%i", tblspcOid); sprintf(params[1], "%i", tblspcOid);
res = pgut_execute(backup_conn, "SELECT pg_catalog.pg_ptrack_get_and_clear_db($1, $2)", res = pgut_execute(backup_conn, "SELECT pg_catalog.pg_ptrack_get_and_clear_db($1, $2)",
2, (const char **)params, true); 2, (const char **)params);
if (PQnfields(res) != 1) if (PQnfields(res) != 1)
elog(ERROR, "cannot perform pg_ptrack_get_and_clear_db()"); elog(ERROR, "cannot perform pg_ptrack_get_and_clear_db()");
@ -1318,7 +1351,7 @@ pg_ptrack_get_and_clear(Oid tablespace_oid, Oid db_oid, Oid rel_filenode,
sprintf(params[0], "%i", db_oid); sprintf(params[0], "%i", db_oid);
res_db = pgut_execute(backup_conn, res_db = pgut_execute(backup_conn,
"SELECT datname FROM pg_database WHERE oid=$1", "SELECT datname FROM pg_database WHERE oid=$1",
1, (const char **) params, true); 1, (const char **) params);
/* /*
* If database is not found, it's not an error. * If database is not found, it's not an error.
* It could have been deleted since previous backup. * It could have been deleted since previous backup.
@ -1338,7 +1371,7 @@ pg_ptrack_get_and_clear(Oid tablespace_oid, Oid db_oid, Oid rel_filenode,
sprintf(params[0], "%i", tablespace_oid); sprintf(params[0], "%i", tablespace_oid);
sprintf(params[1], "%i", rel_filenode); sprintf(params[1], "%i", rel_filenode);
res = pgut_execute(tmp_conn, "SELECT pg_catalog.pg_ptrack_get_and_clear($1, $2)", res = pgut_execute(tmp_conn, "SELECT pg_catalog.pg_ptrack_get_and_clear($1, $2)",
2, (const char **)params, true); 2, (const char **)params);
if (PQnfields(res) != 1) if (PQnfields(res) != 1)
elog(ERROR, "cannot get ptrack file from database \"%s\" by tablespace oid %u and relation oid %u", elog(ERROR, "cannot get ptrack file from database \"%s\" by tablespace oid %u and relation oid %u",
@ -1356,7 +1389,7 @@ pg_ptrack_get_and_clear(Oid tablespace_oid, Oid db_oid, Oid rel_filenode,
sprintf(params[0], "%i", tablespace_oid); sprintf(params[0], "%i", tablespace_oid);
sprintf(params[1], "%i", rel_filenode); sprintf(params[1], "%i", rel_filenode);
res = pgut_execute(backup_conn, "SELECT pg_catalog.pg_ptrack_get_and_clear($1, $2)", res = pgut_execute(backup_conn, "SELECT pg_catalog.pg_ptrack_get_and_clear($1, $2)",
2, (const char **)params, true); 2, (const char **)params);
if (PQnfields(res) != 1) if (PQnfields(res) != 1)
elog(ERROR, "cannot get ptrack file from pg_global tablespace and relation oid %u", elog(ERROR, "cannot get ptrack file from pg_global tablespace and relation oid %u",
@ -1537,10 +1570,10 @@ wait_replica_wal_lsn(XLogRecPtr lsn, bool is_start_backup)
{ {
if (server_version >= 100000) if (server_version >= 100000)
res = pgut_execute(backup_conn, "SELECT pg_catalog.pg_last_wal_replay_lsn()", res = pgut_execute(backup_conn, "SELECT pg_catalog.pg_last_wal_replay_lsn()",
0, NULL, true); 0, NULL);
else else
res = pgut_execute(backup_conn, "SELECT pg_catalog.pg_last_xlog_replay_location()", res = pgut_execute(backup_conn, "SELECT pg_catalog.pg_last_xlog_replay_location()",
0, NULL, true); 0, NULL);
} }
/* /*
* For lsn from pg_stop_backup() we need it only to be received by * For lsn from pg_stop_backup() we need it only to be received by
@ -1550,10 +1583,10 @@ wait_replica_wal_lsn(XLogRecPtr lsn, bool is_start_backup)
{ {
if (server_version >= 100000) if (server_version >= 100000)
res = pgut_execute(backup_conn, "SELECT pg_catalog.pg_last_wal_receive_lsn()", res = pgut_execute(backup_conn, "SELECT pg_catalog.pg_last_wal_receive_lsn()",
0, NULL, true); 0, NULL);
else else
res = pgut_execute(backup_conn, "SELECT pg_catalog.pg_last_xlog_receive_location()", res = pgut_execute(backup_conn, "SELECT pg_catalog.pg_last_xlog_receive_location()",
0, NULL, true); 0, NULL);
} }
/* Extract timeline and LSN from result */ /* Extract timeline and LSN from result */
@ -1620,7 +1653,7 @@ pg_stop_backup(pgBackup *backup)
/* Remove annoying NOTICE messages generated by backend */ /* Remove annoying NOTICE messages generated by backend */
res = pgut_execute(conn, "SET client_min_messages = warning;", res = pgut_execute(conn, "SET client_min_messages = warning;",
0, NULL, true); 0, NULL);
PQclear(res); PQclear(res);
/* Create restore point */ /* Create restore point */
@ -1638,7 +1671,7 @@ pg_stop_backup(pgBackup *backup)
params[0] = name; params[0] = name;
res = pgut_execute(conn, "SELECT pg_catalog.pg_create_restore_point($1)", res = pgut_execute(conn, "SELECT pg_catalog.pg_create_restore_point($1)",
1, params, true); 1, params);
PQclear(res); PQclear(res);
} }
@ -1901,7 +1934,7 @@ checkpoint_timeout(void)
const char *hintmsg; const char *hintmsg;
int val_int; int val_int;
res = pgut_execute(backup_conn, "show checkpoint_timeout", 0, NULL, true); res = pgut_execute(backup_conn, "show checkpoint_timeout", 0, NULL);
val = PQgetvalue(res, 0, 0); val = PQgetvalue(res, 0, 0);
if (!parse_int(val, &val_int, OPTION_UNIT_S, &hintmsg)) if (!parse_int(val, &val_int, OPTION_UNIT_S, &hintmsg))
@ -2586,7 +2619,7 @@ get_last_ptrack_lsn(void)
uint32 xrecoff; uint32 xrecoff;
XLogRecPtr lsn; XLogRecPtr lsn;
res = pgut_execute(backup_conn, "select pg_catalog.pg_ptrack_control_lsn()", 0, NULL, true); res = pgut_execute(backup_conn, "select pg_catalog.pg_ptrack_control_lsn()", 0, NULL);
/* Extract timeline and LSN from results of pg_start_backup() */ /* Extract timeline and LSN from results of pg_start_backup() */
XLogDataFromLSN(PQgetvalue(res, 0, 0), &xlogid, &xrecoff); XLogDataFromLSN(PQgetvalue(res, 0, 0), &xlogid, &xrecoff);

View File

@ -95,8 +95,8 @@ fetchFile(PGconn *conn, const char *filename, size_t *filesize)
int len; int len;
params[0] = filename; params[0] = filename;
res = pgut_execute(conn, "SELECT pg_catalog.pg_read_binary_file($1)", res = pgut_execute_extended(conn, "SELECT pg_catalog.pg_read_binary_file($1)",
1, params, false); 1, params, false, false);
/* sanity check the result set */ /* sanity check the result set */
if (PQntuples(res) != 1 || PQgetisnull(res, 0, 0)) if (PQntuples(res) != 1 || PQgetisnull(res, 0, 0))

View File

@ -251,7 +251,7 @@ main(int argc, char *argv[])
if (argc == 2) if (argc == 2)
{ {
#ifdef PGPRO_VERSION #ifdef PGPRO_VERSION
fprintf(stderr, "%s %s (PostgresPro %s %s)\n", fprintf(stderr, "%s %s (Postgres Pro %s %s)\n",
PROGRAM_NAME, PROGRAM_VERSION, PROGRAM_NAME, PROGRAM_VERSION,
PGPRO_VERSION, PGPRO_EDITION); PGPRO_VERSION, PGPRO_EDITION);
#else #else

View File

@ -149,7 +149,7 @@ get_remote_system_identifier(PGconn *conn)
res = pgut_execute(conn, res = pgut_execute(conn,
"SELECT system_identifier FROM pg_catalog.pg_control_system()", "SELECT system_identifier FROM pg_catalog.pg_control_system()",
0, NULL, true); 0, NULL);
val = PQgetvalue(res, 0, 0); val = PQgetvalue(res, 0, 0);
if (!parse_uint64(val, &system_id_conn, 0)) if (!parse_uint64(val, &system_id_conn, 0))
{ {

View File

@ -1690,11 +1690,19 @@ pgut_execute_parallel(PGconn* conn,
return res; return res;
} }
PGresult * PGresult *
pgut_execute(PGconn* conn, const char *query, int nParams, const char **params, pgut_execute(PGconn* conn, const char *query, int nParams, const char **params)
bool text_result) {
return pgut_execute_extended(conn, query, nParams, params, true, false);
}
PGresult *
pgut_execute_extended(PGconn* conn, const char *query, int nParams,
const char **params, bool text_result, bool ok_error)
{ {
PGresult *res; PGresult *res;
ExecStatusType res_status;
if (interrupted && !in_cleanup) if (interrupted && !in_cleanup)
elog(ERROR, "interrupted"); elog(ERROR, "interrupted");
@ -1730,13 +1738,17 @@ pgut_execute(PGconn* conn, const char *query, int nParams, const char **params,
(text_result) ? 0 : 1); (text_result) ? 0 : 1);
on_after_exec(NULL); on_after_exec(NULL);
switch (PQresultStatus(res)) res_status = PQresultStatus(res);
switch (res_status)
{ {
case PGRES_TUPLES_OK: case PGRES_TUPLES_OK:
case PGRES_COMMAND_OK: case PGRES_COMMAND_OK:
case PGRES_COPY_IN: case PGRES_COPY_IN:
break; break;
default: default:
if (ok_error && res_status == PGRES_FATAL_ERROR)
break;
elog(ERROR, "query failed: %squery was: %s", elog(ERROR, "query failed: %squery was: %s",
PQerrorMessage(conn), query); PQerrorMessage(conn), query);
break; break;

View File

@ -135,7 +135,9 @@ extern PGconn *pgut_connect_replication_extended(const char *pghost, const char
const char *dbname, const char *pguser); const char *dbname, const char *pguser);
extern void pgut_disconnect(PGconn *conn); extern void pgut_disconnect(PGconn *conn);
extern PGresult *pgut_execute(PGconn* conn, const char *query, int nParams, extern PGresult *pgut_execute(PGconn* conn, const char *query, int nParams,
const char **params, bool text_result); const char **params);
extern PGresult *pgut_execute_extended(PGconn* conn, const char *query, int nParams,
const char **params, bool text_result, bool ok_error);
extern PGresult *pgut_execute_parallel(PGconn* conn, PGcancel* thread_cancel_conn, extern PGresult *pgut_execute_parallel(PGconn* conn, PGcancel* thread_cancel_conn,
const char *query, int nParams, const char *query, int nParams,
const char **params, bool text_result); const char **params, bool text_result);