Refactor version number detection

Use the reported `server_version_num` integer for version number
detection and comparison. This makes it easier to set an arbitrary
minimum supported version (rather than "9.0 or later") as well
as future-proofing for 10.x and later.
This commit is contained in:
Ian Barwick
2014-12-29 14:54:04 +09:00
parent 4c64d52afb
commit f94626bf7b
5 changed files with 123 additions and 126 deletions

View File

@@ -178,46 +178,24 @@ is_pgup(PGconn *conn, int timeout)
/* /*
* If postgreSQL version is 9 or superior returns the major version * Return the server version number for the connection provided
* if 8 or inferior returns an empty string
*/ */
char * int
pg_version(PGconn *conn, char *major_version) get_server_version_num(PGconn *conn)
{ {
PGresult *res; PGresult *res;
int major_version1;
char *major_version2;
res = PQexec(conn, res = PQexec(conn,
"WITH pg_version(ver) AS " "SELECT current_setting('server_version_num')");
"(SELECT split_part(version(), ' ', 2)) "
"SELECT split_part(ver, '.', 1), split_part(ver, '.', 2) "
"FROM pg_version");
if (PQresultStatus(res) != PGRES_TUPLES_OK) if (PQresultStatus(res) != PGRES_TUPLES_OK)
{ {
log_err(_("Version check PQexec failed: %s"), log_err(_("Unable to determine server verson number:\n%s"),
PQerrorMessage(conn)); PQerrorMessage(conn));
PQclear(res); PQclear(res);
return NULL; return -1;
} }
major_version1 = atoi(PQgetvalue(res, 0, 0)); return atoi(PQgetvalue(res, 0, 0));
major_version2 = PQgetvalue(res, 0, 1);
if (major_version1 >= 9)
{
/* form a major version string */
xsnprintf(major_version, MAXVERSIONSTR, "%d.%s", major_version1,
major_version2);
}
else
strcpy(major_version, "");
PQclear(res);
return major_version;
} }

View File

@@ -30,7 +30,7 @@ PGconn *establish_db_connection_by_params(const char *keywords[],
int is_standby(PGconn *conn); int is_standby(PGconn *conn);
int is_witness(PGconn *conn, char *schema, char *cluster, int node_id); int is_witness(PGconn *conn, char *schema, char *cluster, int node_id);
bool is_pgup(PGconn *conn, int timeout); bool is_pgup(PGconn *conn, int timeout);
char *pg_version(PGconn *conn, char *major_version); int get_server_version_num(PGconn *conn);
int guc_set(PGconn *conn, const char *parameter, const char *op, int guc_set(PGconn *conn, const char *parameter, const char *op,
const char *value); const char *value);
int guc_set_typed(PGconn *conn, const char *parameter, const char *op, int guc_set_typed(PGconn *conn, const char *parameter, const char *op,

187
repmgr.c
View File

@@ -525,28 +525,30 @@ do_master_register(void)
{ {
PGconn *conn; PGconn *conn;
PGresult *res; PGresult *res;
char sqlquery[QUERY_STR_LEN], char sqlquery[QUERY_STR_LEN];
*ret_ver;
bool schema_exists = false; bool schema_exists = false;
char schema_quoted[MAXLEN]; char schema_quoted[MAXLEN];
char master_version[MAXVERSIONSTR]; int master_version_num = 0;
int ret; int ret;
conn = establish_db_connection(options.conninfo, true); conn = establish_db_connection(options.conninfo, true);
/* master should be v9 or better */ /* Verify that master is a supported server version */
log_info(_("%s connecting to master database\n"), progname); log_info(_("%s connecting to master database\n"), progname);
ret_ver = pg_version(conn, master_version); master_version_num = get_server_version_num(conn);
if (ret_ver == NULL || strcmp(master_version, "") == 0) if(master_version_num < MIN_SUPPORTED_VERSION_NUM)
{ {
PQfinish(conn); PQfinish(conn);
if (ret_ver != NULL) if (master_version_num > 0)
log_err(_("%s needs master to be PostgreSQL 9.0 or better\n"), log_err(_("%s needs master to be PostgreSQL %s or better\n"),
progname); progname,
return; MIN_SUPPORTED_VERSION
);
exit(ERR_BAD_CONFIG);
} }
/* Check we are a master */ /* Check we are a master */
log_info(_("%s connected to master, checking its state\n"), progname); log_info(_("%s connected to master, checking its state\n"), progname);
ret = is_standby(conn); ret = is_standby(conn);
@@ -678,27 +680,27 @@ do_standby_register(void)
ret; ret;
PGresult *res; PGresult *res;
char sqlquery[QUERY_STR_LEN], char sqlquery[QUERY_STR_LEN];
*ret_ver;
char schema_quoted[MAXLEN]; char schema_quoted[MAXLEN];
char master_version[MAXVERSIONSTR]; int master_version_num = 0;
char standby_version[MAXVERSIONSTR]; int standby_version_num = 0;
/* XXX: A lot of copied code from do_master_register! Refactor */ /* XXX: A lot of copied code from do_master_register! Refactor */
log_info(_("%s connecting to standby database\n"), progname); log_info(_("%s connecting to standby database\n"), progname);
conn = establish_db_connection(options.conninfo, true); conn = establish_db_connection(options.conninfo, true);
/* should be v9 or better */ /* Verify that standby is a supported server version */
log_info(_("%s connected to standby, checking its state\n"), progname); standby_version_num = get_server_version_num(conn);
ret_ver = pg_version(conn, standby_version); if(standby_version_num < MIN_SUPPORTED_VERSION_NUM)
if (ret_ver == NULL || strcmp(standby_version, "") == 0)
{ {
PQfinish(conn); PQfinish(conn);
if (ret_ver != NULL) if (standby_version_num > 0)
log_err(_("%s needs standby to be PostgreSQL 9.0 or better\n"), log_err(_("%s needs standby to be PostgreSQL %s or better\n"),
progname); progname,
MIN_SUPPORTED_VERSION
);
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
@@ -733,6 +735,7 @@ do_standby_register(void)
res = PQexec(conn, sqlquery); res = PQexec(conn, sqlquery);
if (PQresultStatus(res) != PGRES_TUPLES_OK) if (PQresultStatus(res) != PGRES_TUPLES_OK)
{ {
/* XXX error message does not match query */
log_err(_("Can't get info about tablespaces: %s\n"), log_err(_("Can't get info about tablespaces: %s\n"),
PQerrorMessage(conn)); PQerrorMessage(conn));
PQclear(res); PQclear(res);
@@ -760,26 +763,29 @@ do_standby_register(void)
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
/* master should be v9 or better */ /* Verify that master is a supported server version */
log_info(_("%s connected to master, checking its state\n"), progname); log_info(_("%s connected to master, checking its state\n"), progname);
ret_ver = pg_version(master_conn, master_version); master_version_num = get_server_version_num(conn);
if (ret_ver == NULL || strcmp(master_version, "") == 0) if(master_version_num < MIN_SUPPORTED_VERSION_NUM)
{ {
if (master_version_num > 0)
log_err(_("%s needs master to be PostgreSQL %s or better\n"),
progname,
MIN_SUPPORTED_VERSION
);
PQfinish(conn); PQfinish(conn);
PQfinish(master_conn); PQfinish(master_conn);
if (ret_ver != NULL)
log_err(_("%s needs master to be PostgreSQL 9.0 or better\n"),
progname);
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
/* master and standby version should match */ /* master and standby version should match */
if (strcmp(master_version, standby_version) != 0) if ((master_version_num / 100) != (standby_version_num / 100))
{ {
PQfinish(conn); PQfinish(conn);
PQfinish(master_conn); PQfinish(master_conn);
log_err(_("%s needs versions of both master (%s) and standby (%s) to match.\n"), /* XXX format version numbers */
progname, master_version, standby_version); log_err(_("%s needs versions of both master (%i) and standby (%i) to match.\n"),
progname, master_version_num, standby_version_num);
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
@@ -835,8 +841,8 @@ do_standby_clone(void)
{ {
PGconn *conn; PGconn *conn;
PGresult *res; PGresult *res;
char sqlquery[QUERY_STR_LEN], char sqlquery[QUERY_STR_LEN];
*ret;
const char *cluster_size; const char *cluster_size;
int r = 0, int r = 0,
@@ -867,7 +873,7 @@ do_standby_clone(void)
char *first_wal_segment = NULL; char *first_wal_segment = NULL;
const char *last_wal_segment = NULL; const char *last_wal_segment = NULL;
char master_version[MAXVERSIONSTR]; int master_version_num = 0;
/* /*
* if dest_dir has been provided, we copy everything in the same path if * if dest_dir has been provided, we copy everything in the same path if
@@ -892,15 +898,18 @@ do_standby_clone(void)
log_info(_("%s connecting to master database\n"), progname); log_info(_("%s connecting to master database\n"), progname);
conn = establish_db_connection_by_params(keywords, values, true); conn = establish_db_connection_by_params(keywords, values, true);
/* primary should be v9 or better */ /* Verify that master is a supported server version */
log_info(_("%s connected to master, checking its state\n"), progname); log_info(_("%s connected to master, checking its state\n"), progname);
ret = pg_version(conn, master_version);
if (ret == NULL || strcmp(master_version, "") == 0) master_version_num = get_server_version_num(conn);
if(master_version_num < MIN_SUPPORTED_VERSION_NUM)
{ {
PQfinish(conn); PQfinish(conn);
if (ret != NULL) if (master_version_num > 0)
log_err(_("%s needs master to be PostgreSQL 9.0 or better\n"), log_err(_("%s needs master to be PostgreSQL %s or better\n"),
progname); progname,
MIN_SUPPORTED_VERSION
);
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
@@ -960,8 +969,7 @@ do_standby_clone(void)
/* /*
* Check if the tablespace locations exists and that we can write to them. * Check if the tablespace locations exists and that we can write to them.
*/ */
if (strcmp(master_version, "9.0") == 0 || if (master_version_num < 90200)
strcmp(master_version, "9.1") == 0)
sqlquery_snprintf(sqlquery, sqlquery_snprintf(sqlquery,
"SELECT spclocation " "SELECT spclocation "
" FROM pg_tablespace " " FROM pg_tablespace "
@@ -1207,8 +1215,7 @@ do_standby_clone(void)
* test_mode but it does not hurt too much (except if a tablespace is * test_mode but it does not hurt too much (except if a tablespace is
* created during the test) * created during the test)
*/ */
if (strcmp(master_version, "9.0") == 0 || if (master_version_num < 90200)
strcmp(master_version, "9.1") == 0)
sqlquery_snprintf(sqlquery, sqlquery_snprintf(sqlquery,
"SELECT spclocation " "SELECT spclocation "
" FROM pg_tablespace " " FROM pg_tablespace "
@@ -1367,8 +1374,8 @@ do_standby_promote(void)
{ {
PGconn *conn; PGconn *conn;
PGresult *res; PGresult *res;
char sqlquery[QUERY_STR_LEN], char sqlquery[QUERY_STR_LEN];
*ret;
char script[MAXLEN]; char script[MAXLEN];
PGconn *old_master_conn; PGconn *old_master_conn;
@@ -1380,21 +1387,24 @@ do_standby_promote(void)
char recovery_file_path[MAXFILENAME]; char recovery_file_path[MAXFILENAME];
char recovery_done_path[MAXFILENAME]; char recovery_done_path[MAXFILENAME];
char standby_version[MAXVERSIONSTR]; int standby_version_num = 0;
/* We need to connect to check configuration */ /* We need to connect to check configuration */
log_info(_("%s connecting to standby database\n"), progname); log_info(_("%s connecting to standby database\n"), progname);
conn = establish_db_connection(options.conninfo, true); conn = establish_db_connection(options.conninfo, true);
/* we need v9 or better */ /* Verify that standby is a supported server version */
log_info(_("%s connected to standby, checking its state\n"), progname); log_info(_("%s connected to standby, checking its state\n"), progname);
ret = pg_version(conn, standby_version);
if (ret == NULL || strcmp(standby_version, "") == 0) standby_version_num = get_server_version_num(conn);
if(standby_version_num < MIN_SUPPORTED_VERSION_NUM)
{ {
if (ret != NULL)
log_err(_("%s needs standby to be PostgreSQL 9.0 or better\n"),
progname);
PQfinish(conn); PQfinish(conn);
if (standby_version_num > 0)
log_err(_("%s needs standby to be PostgreSQL %s or better\n"),
progname,
MIN_SUPPORTED_VERSION
);
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
@@ -1485,8 +1495,7 @@ do_standby_follow(void)
{ {
PGconn *conn; PGconn *conn;
PGresult *res; PGresult *res;
char sqlquery[QUERY_STR_LEN], char sqlquery[QUERY_STR_LEN];
*ret;
char script[MAXLEN]; char script[MAXLEN];
char master_conninfo[MAXLEN]; char master_conninfo[MAXLEN];
PGconn *master_conn; PGconn *master_conn;
@@ -1496,13 +1505,27 @@ do_standby_follow(void)
retval; retval;
char data_dir[MAXLEN]; char data_dir[MAXLEN];
char master_version[MAXVERSIONSTR]; int master_version_num = 0;
char standby_version[MAXVERSIONSTR]; int standby_version_num = 0;
/* We need to connect to check configuration */ /* We need to connect to check configuration */
log_info(_("%s connecting to standby database\n"), progname); log_info(_("%s connecting to standby database\n"), progname);
conn = establish_db_connection(options.conninfo, true); conn = establish_db_connection(options.conninfo, true);
/* Verify that standby is a supported server version */
standby_version_num = get_server_version_num(conn);
if(standby_version_num < MIN_SUPPORTED_VERSION_NUM)
{
PQfinish(conn);
if (standby_version_num > 0)
log_err(_("%s needs standby to be PostgreSQL %s or better\n"),
progname,
MIN_SUPPORTED_VERSION
);
exit(ERR_BAD_CONFIG);
}
/* Check we are in a standby node */ /* Check we are in a standby node */
log_info(_("%s connected to standby, checking its state\n"), progname); log_info(_("%s connected to standby, checking its state\n"), progname);
retval = is_standby(conn); retval = is_standby(conn);
@@ -1515,17 +1538,6 @@ do_standby_follow(void)
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
/* should be v9 or better */
ret = pg_version(conn, standby_version);
if (ret == NULL || strcmp(standby_version, "") == 0)
{
if (ret != NULL)
log_err(_("%s needs standby to be PostgreSQL 9.0 or better\n"),
progname);
PQfinish(conn);
exit(ERR_BAD_CONFIG);
}
/* /*
* we also need to check if there is any master in the cluster or wait for * we also need to check if there is any master in the cluster or wait for
* one to appear if we have set the wait option * one to appear if we have set the wait option
@@ -1563,26 +1575,29 @@ do_standby_follow(void)
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
/* should be v9 or better */ /* Verify that master is a supported server version */
log_info(_("%s connected to master, checking its state\n"), progname); log_info(_("%s connected to master, checking its state\n"), progname);
ret = pg_version(master_conn, master_version); master_version_num = get_server_version_num(conn);
if (ret == NULL || strcmp(master_version, "") == 0) if(master_version_num < MIN_SUPPORTED_VERSION_NUM)
{ {
if (ret != NULL) if (master_version_num > 0)
log_err(_("%s needs master to be PostgreSQL 9.0 or better\n"), log_err(_("%s needs master to be PostgreSQL %s or better\n"),
progname); progname,
MIN_SUPPORTED_VERSION
);
PQfinish(conn); PQfinish(conn);
PQfinish(master_conn); PQfinish(master_conn);
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
/* master and standby version should match */ /* master and standby version should match */
if (strcmp(master_version, standby_version) != 0) if ((master_version_num / 100) != (standby_version_num / 100))
{ {
log_err(_("%s needs versions of both master (%s) and standby (%s) to match.\n"),
progname, master_version, standby_version);
PQfinish(conn); PQfinish(conn);
PQfinish(master_conn); PQfinish(master_conn);
/* XXX format version numbers */
log_err(_("%s needs versions of both master (%i) and standby (%i) to match.\n"),
progname, master_version_num, standby_version_num);
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
@@ -1639,8 +1654,7 @@ do_witness_create(void)
PGconn *masterconn; PGconn *masterconn;
PGconn *witnessconn; PGconn *witnessconn;
PGresult *res; PGresult *res;
char sqlquery[QUERY_STR_LEN], char sqlquery[QUERY_STR_LEN];
*ret;
char script[MAXLEN]; char script[MAXLEN];
char buf[MAXLEN]; char buf[MAXLEN];
@@ -1650,9 +1664,8 @@ do_witness_create(void)
retval; retval;
int i; int i;
char master_version[MAXVERSIONSTR];
char master_hba_file[MAXLEN]; char master_hba_file[MAXLEN];
int master_version_num = 0;
/* Connection parameters for master only */ /* Connection parameters for master only */
keywords[0] = "host"; keywords[0] = "host";
@@ -1668,14 +1681,16 @@ do_witness_create(void)
exit(ERR_DB_CON); exit(ERR_DB_CON);
} }
/* primary should be v9 or better */ /* Verify that master is a supported server version */
ret = pg_version(masterconn, master_version); master_version_num = get_server_version_num(masterconn);
if (ret == NULL || strcmp(master_version, "") == 0) if(master_version_num < MIN_SUPPORTED_VERSION_NUM)
{ {
if (ret != NULL)
log_err(_("%s needs master to be PostgreSQL 9.0 or better\n"),
progname);
PQfinish(masterconn); PQfinish(masterconn);
if (master_version_num > 0)
log_err(_("%s needs master to be PostgreSQL %s or better\n"),
progname,
MIN_SUPPORTED_VERSION
);
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }

View File

@@ -32,6 +32,9 @@
#define STANDBY_MODE 1 #define STANDBY_MODE 1
#define WITNESS_MODE 2 #define WITNESS_MODE 2
#define MIN_SUPPORTED_VERSION "9.1"
#define MIN_SUPPORTED_VERSION_NUM 90100
#include "config.h" #include "config.h"
#define MAXFILENAME 1024 #define MAXFILENAME 1024
#define ERRBUFF_SIZE 512 #define ERRBUFF_SIZE 512
@@ -46,6 +49,7 @@
#define MANUAL_FAILOVER 0 #define MANUAL_FAILOVER 0
#define AUTOMATIC_FAILOVER 1 #define AUTOMATIC_FAILOVER 1
/* Run time options type */ /* Run time options type */
typedef struct typedef struct
{ {

View File

@@ -174,9 +174,7 @@ main(int argc, char **argv)
bool daemonize = false; bool daemonize = false;
FILE *fd; FILE *fd;
char standby_version[MAXVERSIONSTR], int server_version_num = 0;
*ret_ver;
progname = get_progname(argv[0]); progname = get_progname(argv[0]);
if (argc > 1) if (argc > 1)
@@ -280,14 +278,16 @@ main(int argc, char **argv)
local_options.conninfo); local_options.conninfo);
my_local_conn = establish_db_connection(local_options.conninfo, true); my_local_conn = establish_db_connection(local_options.conninfo, true);
/* should be v9 or better */ /* Verify that server is a supported version */
log_info(_("%s Connected to database, checking its state\n"), progname); log_info(_("%s connected to database, checking its state\n"), progname);
ret_ver = pg_version(my_local_conn, standby_version); server_version_num = get_server_version_num(my_local_conn);
if (ret_ver == NULL || strcmp(standby_version, "") == 0) if(server_version_num < MIN_SUPPORTED_VERSION_NUM)
{ {
if (ret_ver != NULL) if (server_version_num > 0)
log_err(_("%s needs standby to be PostgreSQL 9.0 or better\n"), log_err(_("%s requires PostgreSQL %s or better\n"),
progname); progname,
MIN_SUPPORTED_VERSION
);
terminate(ERR_BAD_CONFIG); terminate(ERR_BAD_CONFIG);
} }