From d8005d5496081910bd0549207a65d179a00527f1 Mon Sep 17 00:00:00 2001 From: Arthur Zakirov Date: Wed, 16 May 2018 10:00:49 +0300 Subject: [PATCH] PGPRO-1290: Check connected server version with build version --- src/backup.c | 91 +++++++++++++++++++++++++++++++--------------- src/fetch.c | 4 +- src/pg_probackup.c | 2 +- src/util.c | 2 +- src/utils/pgut.c | 18 +++++++-- src/utils/pgut.h | 4 +- 6 files changed, 84 insertions(+), 37 deletions(-) diff --git a/src/backup.c b/src/backup.c index 68e1982a..83b311c4 100644 --- a/src/backup.c +++ b/src/backup.c @@ -934,6 +934,8 @@ do_backup(time_t start_time) static void check_server_version(void) { + PGresult *res; + /* confirm server version */ 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_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 */ exclusive_backup = server_version < 90600 || current.backup_mode == BACKUP_MODE_DIFF_PTRACK; @@ -997,7 +1032,7 @@ confirm_block_size(const char *name, int blcksz) char *endp; 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) 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, "SELECT pg_catalog.pg_start_backup($1, $2, false)", 2, - params, - true); + params); else res = pgut_execute(conn, "SELECT pg_catalog.pg_start_backup($1, $2)", 2, - params, - true); + params); /* Extract timeline and LSN from results of pg_start_backup() */ XLogDataFromLSN(PQgetvalue(res, 0, 0), &xlogid, &xrecoff); @@ -1091,13 +1124,13 @@ pg_switch_wal(PGconn *conn) PGresult *res; /* 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); 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 - 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); } @@ -1113,7 +1146,7 @@ pg_ptrack_support(void) res_db = pgut_execute(backup_conn, "SELECT proname FROM pg_proc WHERE proname='ptrack_version'", - 0, NULL, true); + 0, NULL); if (PQntuples(res_db) == 0) { PQclear(res_db); @@ -1123,7 +1156,7 @@ pg_ptrack_support(void) res_db = pgut_execute(backup_conn, "SELECT pg_catalog.ptrack_version()", - 0, NULL, true); + 0, NULL); if (PQntuples(res_db) == 0) { PQclear(res_db); @@ -1148,7 +1181,7 @@ pg_ptrack_enable(void) { 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) { @@ -1165,7 +1198,7 @@ pg_checksum_enable(void) { 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) { @@ -1182,7 +1215,7 @@ pg_is_in_recovery(void) { 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') { @@ -1207,7 +1240,7 @@ pg_ptrack_clear(void) params[0] = palloc(64); params[1] = palloc(64); 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++) { @@ -1221,12 +1254,12 @@ pg_ptrack_clear(void) tblspcOid = atoi(PQgetvalue(res_db, i, 2)); 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[1], "%i", tblspcOid); 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); pgut_disconnect(tmp_conn); @@ -1252,7 +1285,7 @@ pg_ptrack_get_and_clear_db(Oid dbOid, Oid tblspcOid) sprintf(params[0], "%i", dbOid); res_db = pgut_execute(backup_conn, "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. * 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[1], "%i", tblspcOid); 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) 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); res_db = pgut_execute(backup_conn, "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. * 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[1], "%i", rel_filenode); 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) 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[1], "%i", rel_filenode); 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) 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) res = pgut_execute(backup_conn, "SELECT pg_catalog.pg_last_wal_replay_lsn()", - 0, NULL, true); + 0, NULL); else 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 @@ -1550,10 +1583,10 @@ wait_replica_wal_lsn(XLogRecPtr lsn, bool is_start_backup) { if (server_version >= 100000) res = pgut_execute(backup_conn, "SELECT pg_catalog.pg_last_wal_receive_lsn()", - 0, NULL, true); + 0, NULL); else res = pgut_execute(backup_conn, "SELECT pg_catalog.pg_last_xlog_receive_location()", - 0, NULL, true); + 0, NULL); } /* Extract timeline and LSN from result */ @@ -1620,7 +1653,7 @@ pg_stop_backup(pgBackup *backup) /* Remove annoying NOTICE messages generated by backend */ res = pgut_execute(conn, "SET client_min_messages = warning;", - 0, NULL, true); + 0, NULL); PQclear(res); /* Create restore point */ @@ -1638,7 +1671,7 @@ pg_stop_backup(pgBackup *backup) params[0] = name; res = pgut_execute(conn, "SELECT pg_catalog.pg_create_restore_point($1)", - 1, params, true); + 1, params); PQclear(res); } @@ -1901,7 +1934,7 @@ checkpoint_timeout(void) const char *hintmsg; 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); if (!parse_int(val, &val_int, OPTION_UNIT_S, &hintmsg)) @@ -2586,7 +2619,7 @@ get_last_ptrack_lsn(void) uint32 xrecoff; 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() */ XLogDataFromLSN(PQgetvalue(res, 0, 0), &xlogid, &xrecoff); diff --git a/src/fetch.c b/src/fetch.c index a6ff9d33..0d4dbdaa 100644 --- a/src/fetch.c +++ b/src/fetch.c @@ -95,8 +95,8 @@ fetchFile(PGconn *conn, const char *filename, size_t *filesize) int len; params[0] = filename; - res = pgut_execute(conn, "SELECT pg_catalog.pg_read_binary_file($1)", - 1, params, false); + res = pgut_execute_extended(conn, "SELECT pg_catalog.pg_read_binary_file($1)", + 1, params, false, false); /* sanity check the result set */ if (PQntuples(res) != 1 || PQgetisnull(res, 0, 0)) diff --git a/src/pg_probackup.c b/src/pg_probackup.c index 87ae2889..5d464171 100644 --- a/src/pg_probackup.c +++ b/src/pg_probackup.c @@ -251,7 +251,7 @@ main(int argc, char *argv[]) if (argc == 2) { #ifdef PGPRO_VERSION - fprintf(stderr, "%s %s (PostgresPro %s %s)\n", + fprintf(stderr, "%s %s (Postgres Pro %s %s)\n", PROGRAM_NAME, PROGRAM_VERSION, PGPRO_VERSION, PGPRO_EDITION); #else diff --git a/src/util.c b/src/util.c index 7f2c29ca..f2c84f6e 100644 --- a/src/util.c +++ b/src/util.c @@ -149,7 +149,7 @@ get_remote_system_identifier(PGconn *conn) res = pgut_execute(conn, "SELECT system_identifier FROM pg_catalog.pg_control_system()", - 0, NULL, true); + 0, NULL); val = PQgetvalue(res, 0, 0); if (!parse_uint64(val, &system_id_conn, 0)) { diff --git a/src/utils/pgut.c b/src/utils/pgut.c index fdd3390a..56263cfa 100644 --- a/src/utils/pgut.c +++ b/src/utils/pgut.c @@ -1690,11 +1690,19 @@ pgut_execute_parallel(PGconn* conn, return res; } + PGresult * -pgut_execute(PGconn* conn, const char *query, int nParams, const char **params, - bool text_result) +pgut_execute(PGconn* conn, const char *query, int nParams, const char **params) +{ + 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; + ExecStatusType res_status; if (interrupted && !in_cleanup) elog(ERROR, "interrupted"); @@ -1730,13 +1738,17 @@ pgut_execute(PGconn* conn, const char *query, int nParams, const char **params, (text_result) ? 0 : 1); on_after_exec(NULL); - switch (PQresultStatus(res)) + res_status = PQresultStatus(res); + switch (res_status) { case PGRES_TUPLES_OK: case PGRES_COMMAND_OK: case PGRES_COPY_IN: break; default: + if (ok_error && res_status == PGRES_FATAL_ERROR) + break; + elog(ERROR, "query failed: %squery was: %s", PQerrorMessage(conn), query); break; diff --git a/src/utils/pgut.h b/src/utils/pgut.h index d4042c9d..a9003f2f 100644 --- a/src/utils/pgut.h +++ b/src/utils/pgut.h @@ -135,7 +135,9 @@ extern PGconn *pgut_connect_replication_extended(const char *pghost, const char const char *dbname, const char *pguser); extern void pgut_disconnect(PGconn *conn); 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, const char *query, int nParams, const char **params, bool text_result);