diff --git a/src/backup.c b/src/backup.c index 80042625..6c248b9f 100644 --- a/src/backup.c +++ b/src/backup.c @@ -915,32 +915,15 @@ check_server_version(void) static void check_system_identifiers(void) { - PGresult *res; uint64 system_id_conn; uint64 system_id_pgdata; - char *val; system_id_pgdata = get_system_identifier(pgdata); + system_id_conn = get_remote_system_identifier(backup_conn); - if (server_version < 90600) { - // Skip match system_identifier between backup data directory and DB connection as - // pg_control_system() exists only in 9.6 onwards - } else { - res = pgut_execute(backup_conn, - "SELECT system_identifier FROM pg_control_system()", - 0, NULL, true); - val = PQgetvalue(res, 0, 0); - if (!parse_uint64(val, &system_id_conn, 0)) - { - PQclear(res); - elog(ERROR, "%s is not system_identifier", val); - } - PQclear(res); - - if (system_id_conn != system_identifier) - elog(ERROR, "Backup data directory was initialized for system id %ld, but connected instance system id is %ld", - system_identifier, system_id_conn); - } + if (system_id_conn != system_identifier) + elog(ERROR, "Backup data directory was initialized for system id %ld, but connected instance system id is %ld", + system_identifier, system_id_conn); if (system_id_pgdata != system_identifier) elog(ERROR, "Backup data directory was initialized for system id %ld, but target backup directory system id is %ld", system_identifier, system_id_pgdata); diff --git a/src/fetch.c b/src/fetch.c index c9cc4459..1f711ec5 100644 --- a/src/fetch.c +++ b/src/fetch.c @@ -82,3 +82,35 @@ slurpFile(const char *datadir, const char *path, size_t *filesize, bool safe) *filesize = len; return buffer; } + +/* + * Receive a single file as a malloc'd buffer. + */ +char * +fetchFile(PGconn *conn, const char *filename, size_t *filesize) +{ + PGresult *res; + char *result; + const char *params[1]; + int len; + + params[0] = filename; + res = pgut_execute(conn, "SELECT pg_read_binary_file($1)", + 1, params, false); + + /* sanity check the result set */ + if (PQntuples(res) != 1 || PQgetisnull(res, 0, 0)) + elog(ERROR, "unexpected result set while fetching remote file \"%s\"", + filename); + + /* Read result to local variables */ + len = PQgetlength(res, 0, 0); + result = pg_malloc(len + 1); + memcpy(result, PQgetvalue(res, 0, 0), len); + result[len] = '\0'; + + PQclear(res); + *filesize = len; + + return result; +} diff --git a/src/pg_probackup.h b/src/pg_probackup.h index 7c41df86..c44feb0e 100644 --- a/src/pg_probackup.h +++ b/src/pg_probackup.h @@ -367,6 +367,7 @@ extern char *slurpFile(const char *datadir, const char *path, size_t *filesize, bool safe); +extern char *fetchFile(PGconn *conn, const char *filename, size_t *filesize); /* in help.c */ extern void help_pg_probackup(void); @@ -458,6 +459,7 @@ extern uint32 get_data_checksum_version(bool safe); extern char *base36enc(long unsigned int value); extern long unsigned int base36dec(const char *text); extern uint64 get_system_identifier(char *pgdata); +extern uint64 get_remote_system_identifier(PGconn *conn); extern pg_time_t timestamptz_to_time_t(TimestampTz t); extern void pgBackup_init(pgBackup *backup); diff --git a/src/util.c b/src/util.c index 217f7a8a..998035ee 100644 --- a/src/util.c +++ b/src/util.c @@ -120,6 +120,39 @@ get_system_identifier(char *pgdata_path) return ControlFile.system_identifier; } +uint64 +get_remote_system_identifier(PGconn *conn) +{ +#if PG_VERSION_NUM >= 90600 + PGresult *res; + uint64 system_id_conn; + char *val; + + res = pgut_execute(conn, + "SELECT system_identifier FROM pg_control_system()", + 0, NULL, true); + val = PQgetvalue(res, 0, 0); + if (!parse_uint64(val, &system_id_conn, 0)) + { + PQclear(res); + elog(ERROR, "%s is not system_identifier", val); + } + PQclear(res); + + return system_id_conn; +#else + char *buffer; + size_t size; + ControlFileData ControlFile; + + buffer = fetchFile(conn, "global/pg_control", &size); + digestControlFile(&ControlFile, buffer, size); + pg_free(buffer); + + return ControlFile.system_identifier; +#endif +} + uint32 get_data_checksum_version(bool safe) { diff --git a/src/utils/pgut.c b/src/utils/pgut.c index 1b82b450..f2980dbd 100644 --- a/src/utils/pgut.c +++ b/src/utils/pgut.c @@ -1498,7 +1498,7 @@ pgut_set_port(const char *new_port) PGresult * pgut_execute(PGconn* conn, const char *query, int nParams, const char **params, - bool exit_on_error) + bool text_result) { PGresult *res; @@ -1528,22 +1528,24 @@ pgut_execute(PGconn* conn, const char *query, int nParams, const char **params, if (nParams == 0) res = PQexec(conn, query); else - res = PQexecParams(conn, query, nParams, NULL, params, NULL, NULL, 0); + res = PQexecParams(conn, query, nParams, NULL, params, NULL, NULL, + /* + * Specify zero to obtain results in text format, + * or one to obtain results in binary format. + */ + (text_result) ? 0 : 1); on_after_exec(); - if (exit_on_error) + switch (PQresultStatus(res)) { - switch (PQresultStatus(res)) - { - case PGRES_TUPLES_OK: - case PGRES_COMMAND_OK: - case PGRES_COPY_IN: - break; - default: - elog(ERROR, "query failed: %squery was: %s", - PQerrorMessage(conn), query); - break; - } + case PGRES_TUPLES_OK: + case PGRES_COMMAND_OK: + case PGRES_COPY_IN: + break; + default: + elog(ERROR, "query failed: %squery was: %s", + PQerrorMessage(conn), query); + break; } return res; diff --git a/src/utils/pgut.h b/src/utils/pgut.h index 00a76fdc..572cc693 100644 --- a/src/utils/pgut.h +++ b/src/utils/pgut.h @@ -125,7 +125,8 @@ extern PGconn *pgut_connect_replication_extended(const char *pghost, const char const char *dbname, const char *login, const char *pwd); extern void pgut_disconnect(PGconn *conn); -extern PGresult *pgut_execute(PGconn* conn, const char *query, int nParams, const char **params, bool exit_on_error); +extern PGresult *pgut_execute(PGconn* conn, const char *query, int nParams, + const char **params, bool text_result); extern bool pgut_send(PGconn* conn, const char *query, int nParams, const char **params, int elevel); extern void pgut_cancel(PGconn* conn); extern int pgut_wait(int num, PGconn *connections[], struct timeval *timeout);