Refactor server version detection

Most of the time we can simply get the version number directly from
the connection handle. Previously it was held in a global variable,
which was an icky way of doing things.

In a few special cases we also need the actual version string, which
is obtained directly from the database.
This commit is contained in:
Ian Barwick
2018-11-22 20:34:01 +09:00
parent 0f4e04e61e
commit 793d83b22c
6 changed files with 45 additions and 122 deletions

107
dbutils.c
View File

@@ -32,8 +32,6 @@
#define NODE_RECORD_PARAM_COUNT 11 #define NODE_RECORD_PARAM_COUNT 11
/* mainly for use by repmgrd */
int server_version_num = UNKNOWN_SERVER_VERSION_NUM;
/* /*
* This is set by is_bdr_db(), which is called by every BDR-related * This is set by is_bdr_db(), which is called by every BDR-related
@@ -1096,14 +1094,16 @@ get_cluster_size(PGconn *conn, char *size)
return success; return success;
} }
/* /*
* Return the server version number for the connection provided * Return the server version number for the connection provided
*/ */
int int
get_server_version(PGconn *conn, char *server_version) get_server_version(PGconn *conn, char *server_version_buf)
{ {
PGresult *res = NULL; PGresult *res = NULL;
int server_version_num; int _server_version_num = UNKNOWN_SERVER_VERSION_NUM;
const char *sqlquery = const char *sqlquery =
"SELECT pg_catalog.current_setting('server_version_num'), " "SELECT pg_catalog.current_setting('server_version_num'), "
" pg_catalog.current_setting('server_version')"; " pg_catalog.current_setting('server_version')";
@@ -1115,15 +1115,17 @@ get_server_version(PGconn *conn, char *server_version)
log_db_error(conn, sqlquery, _("unable to determine server version number")); log_db_error(conn, sqlquery, _("unable to determine server version number"));
PQclear(res); PQclear(res);
return -1; return UNKNOWN_SERVER_VERSION_NUM;
} }
if (server_version != NULL) _server_version_num = atoi(PQgetvalue(res, 0, 0));
{
char server_version_buf[MAXVERSIONSTR];
int i;
memset(server_version_buf, 0, MAXVERSIONSTR); if (server_version_buf != NULL)
{
int i;
char _server_version_buf[MAXVERSIONSTR] = "";
memset(_server_version_buf, 0, MAXVERSIONSTR);
/* /*
* Some distributions may add extra info after the actual version number, * Some distributions may add extra info after the actual version number,
@@ -1131,22 +1133,20 @@ get_server_version(PGconn *conn, char *server_version)
* first space. * first space.
*/ */
strncpy(server_version_buf, PQgetvalue(res, 0, 1), MAXVERSIONSTR); strncpy(_server_version_buf, PQgetvalue(res, 0, 1), MAXVERSIONSTR);
for (i = 0; i < MAXVERSIONSTR; i++) for (i = 0; i < MAXVERSIONSTR; i++)
{ {
if (server_version_buf[i] == ' ') if (_server_version_buf[i] == ' ')
break; break;
*server_version++ = server_version_buf[i]; *server_version_buf++ = _server_version_buf[i];
} }
} }
server_version_num = atoi(PQgetvalue(res, 0, 0));
PQclear(res); PQclear(res);
return server_version_num; return _server_version_num;
} }
@@ -1382,9 +1382,6 @@ get_replication_info(PGconn *conn, ReplInfo *replication_info)
PGresult *res = NULL; PGresult *res = NULL;
bool success = true; bool success = true;
if (server_version_num == UNKNOWN_SERVER_VERSION_NUM)
server_version_num = get_server_version(conn, NULL);
initPQExpBuffer(&query); initPQExpBuffer(&query);
appendPQExpBufferStr(&query, appendPQExpBufferStr(&query,
" SELECT ts, " " SELECT ts, "
@@ -1399,7 +1396,7 @@ get_replication_info(PGconn *conn, ReplInfo *replication_info)
" COALESCE(last_wal_receive_lsn, '0/0') >= last_wal_replay_lsn AS receiving_streamed_wal " " COALESCE(last_wal_receive_lsn, '0/0') >= last_wal_replay_lsn AS receiving_streamed_wal "
" FROM ( "); " FROM ( ");
if (server_version_num >= 100000) if (PQserverVersion(conn) >= 100000)
{ {
appendPQExpBufferStr(&query, appendPQExpBufferStr(&query,
" SELECT CURRENT_TIMESTAMP AS ts, " " SELECT CURRENT_TIMESTAMP AS ts, "
@@ -1456,10 +1453,7 @@ get_ready_archive_files(PGconn *conn, const char *data_directory)
int ready_count = 0; int ready_count = 0;
if (server_version_num == UNKNOWN_SERVER_VERSION_NUM) if (PQserverVersion(conn) >= 100000)
server_version_num = get_server_version(conn, NULL);
if (server_version_num >= 100000)
{ {
snprintf(archive_status_dir, MAXPGPATH, snprintf(archive_status_dir, MAXPGPATH,
"%s/pg_wal/archive_status", "%s/pg_wal/archive_status",
@@ -1533,12 +1527,9 @@ get_replication_lag_seconds(PGconn *conn)
PGresult *res = NULL; PGresult *res = NULL;
int lag_seconds = 0; int lag_seconds = 0;
if (server_version_num == UNKNOWN_SERVER_VERSION_NUM)
server_version_num = get_server_version(conn, NULL);
initPQExpBuffer(&query); initPQExpBuffer(&query);
if (server_version_num >= 100000) if (PQserverVersion(conn) >= 100000)
{ {
appendPQExpBufferStr(&query, appendPQExpBufferStr(&query,
" SELECT CASE WHEN (pg_catalog.pg_last_wal_receive_lsn() = pg_catalog.pg_last_wal_replay_lsn()) "); " SELECT CASE WHEN (pg_catalog.pg_last_wal_receive_lsn() = pg_catalog.pg_last_wal_replay_lsn()) ");
@@ -3107,16 +3098,11 @@ update_node_record_slot_name(PGconn *primary_conn, int node_id, char *slot_name)
void void
get_node_replication_stats(PGconn *conn, int server_version_num, t_node_info *node_info) get_node_replication_stats(PGconn *conn, t_node_info *node_info)
{ {
PQExpBufferData query; PQExpBufferData query;
PGresult *res = NULL; PGresult *res = NULL;
if (server_version_num == UNKNOWN_SERVER_VERSION_NUM)
server_version_num = get_server_version(conn, NULL);
Assert(server_version_num != UNKNOWN_SERVER_VERSION_NUM);
initPQExpBuffer(&query); initPQExpBuffer(&query);
appendPQExpBufferStr(&query, appendPQExpBufferStr(&query,
@@ -3124,7 +3110,7 @@ get_node_replication_stats(PGconn *conn, int server_version_num, t_node_info *no
" (SELECT pg_catalog.count(*) FROM pg_catalog.pg_stat_replication) AS attached_wal_receivers, "); " (SELECT pg_catalog.count(*) FROM pg_catalog.pg_stat_replication) AS attached_wal_receivers, ");
/* no replication slots in PostgreSQL 9.3 */ /* no replication slots in PostgreSQL 9.3 */
if (server_version_num < 90400) if (PQserverVersion(conn) < 90400)
{ {
appendPQExpBufferStr(&query, appendPQExpBufferStr(&query,
" 0 AS max_replication_slots, " " 0 AS max_replication_slots, "
@@ -3958,9 +3944,6 @@ create_replication_slot(PGconn *conn, char *slot_name, int server_version_num, P
PGresult *res = NULL; PGresult *res = NULL;
t_replication_slot slot_info = T_REPLICATION_SLOT_INITIALIZER; t_replication_slot slot_info = T_REPLICATION_SLOT_INITIALIZER;
if (server_version_num == UNKNOWN_SERVER_VERSION_NUM)
server_version_num = get_server_version(conn, NULL);
/* /*
* Check whether slot exists already; if it exists and is active, that * Check whether slot exists already; if it exists and is active, that
* means another active standby is using it, which creates an error * means another active standby is using it, which creates an error
@@ -3997,7 +3980,7 @@ create_replication_slot(PGconn *conn, char *slot_name, int server_version_num, P
initPQExpBuffer(&query); initPQExpBuffer(&query);
/* In 9.6 and later, reserve the LSN straight away */ /* In 9.6 and later, reserve the LSN straight away */
if (server_version_num >= 90600) if (PQserverVersion(conn) >= 90600)
{ {
appendPQExpBuffer(&query, appendPQExpBuffer(&query,
"SELECT * FROM pg_catalog.pg_create_physical_replication_slot('%s', TRUE)", "SELECT * FROM pg_catalog.pg_create_physical_replication_slot('%s', TRUE)",
@@ -4762,7 +4745,7 @@ get_current_wal_lsn(PGconn *conn)
PGresult *res = NULL; PGresult *res = NULL;
XLogRecPtr ptr = InvalidXLogRecPtr; XLogRecPtr ptr = InvalidXLogRecPtr;
if (server_version_num >= 100000) if (PQserverVersion(conn) >= 100000)
{ {
res = PQexec(conn, "SELECT pg_catalog.pg_current_wal_lsn()"); res = PQexec(conn, "SELECT pg_catalog.pg_current_wal_lsn()");
} }
@@ -4787,7 +4770,7 @@ get_last_wal_receive_location(PGconn *conn)
PGresult *res = NULL; PGresult *res = NULL;
XLogRecPtr ptr = InvalidXLogRecPtr; XLogRecPtr ptr = InvalidXLogRecPtr;
if (server_version_num >= 100000) if (PQserverVersion(conn) >= 100000)
{ {
res = PQexec(conn, "SELECT pg_catalog.pg_last_wal_receive_lsn()"); res = PQexec(conn, "SELECT pg_catalog.pg_last_wal_receive_lsn()");
} }
@@ -4815,47 +4798,7 @@ get_current_lsn(PGconn *conn)
initPQExpBuffer(&query); initPQExpBuffer(&query);
if (server_version_num == UNKNOWN_SERVER_VERSION_NUM) if (PQserverVersion(conn) >= 100000)
server_version_num = get_server_version(conn, NULL);
/*
WITH lsn_states AS (
SELECT
CASE WHEN pg_catalog.pg_is_in_recovery() IS FALSE
THEN pg_catalog.pg_current_wal_lsn()
ELSE NULL
END
AS current_wal_lsn,
CASE WHEN pg_catalog.pg_is_in_recovery() IS TRUE
THEN pg_catalog.pg_last_wal_receive_lsn()
ELSE NULL
END
AS last_wal_receive_lsn,
CASE WHEN pg_catalog.pg_is_in_recovery() IS TRUE
THEN pg_catalog.pg_last_wal_replay_lsn()
ELSE NULL
END
AS last_wal_replay_lsn
)
SELECT
CASE WHEN pg_catalog.pg_is_in_recovery() IS FALSE
THEN current_wal_lsn
ELSE
CASE WHEN last_wal_receive_lsn IS NULL
THEN last_wal_replay_lsn
ELSE
CASE WHEN last_wal_replay_lsn > last_wal_receive_lsn
THEN last_wal_replay_lsn
ELSE last_wal_receive_lsn
END
END
END
AS current_lsn
FROM lsn_states
*/
if (server_version_num >= 100000)
{ {
appendPQExpBufferStr(&query, appendPQExpBufferStr(&query,
" WITH lsn_states AS ( " " WITH lsn_states AS ( "

View File

@@ -358,10 +358,6 @@ typedef struct RepmgrdInfo {
} RepmgrdInfo; } RepmgrdInfo;
/* global variables */
extern int server_version_num;
/* macros */ /* macros */
#define is_streaming_replication(x) (x == PRIMARY || x == STANDBY) #define is_streaming_replication(x) (x == PRIMARY || x == STANDBY)
@@ -420,7 +416,8 @@ bool get_pg_setting(PGconn *conn, const char *setting, char *output);
/* server information functions */ /* server information functions */
bool get_cluster_size(PGconn *conn, char *size); bool get_cluster_size(PGconn *conn, char *size);
int get_server_version(PGconn *conn, char *server_version); int get_server_version(PGconn *conn, char *server_version_buf);
RecoveryType get_recovery_type(PGconn *conn); RecoveryType get_recovery_type(PGconn *conn);
int get_primary_node_id(PGconn *conn); int get_primary_node_id(PGconn *conn);
int get_ready_archive_files(PGconn *conn, const char *data_directory); int get_ready_archive_files(PGconn *conn, const char *data_directory);
@@ -548,7 +545,7 @@ XLogRecPtr get_last_wal_receive_location(PGconn *conn);
XLogRecPtr get_current_lsn(PGconn *conn); XLogRecPtr get_current_lsn(PGconn *conn);
bool get_replication_info(PGconn *conn, ReplInfo *replication_info); bool get_replication_info(PGconn *conn, ReplInfo *replication_info);
int get_replication_lag_seconds(PGconn *conn); int get_replication_lag_seconds(PGconn *conn);
void get_node_replication_stats(PGconn *conn, int server_version_num, t_node_info *node_info); void get_node_replication_stats(PGconn *conn, t_node_info *node_info);
bool is_downstream_node_attached(PGconn *conn, char *node_name); bool is_downstream_node_attached(PGconn *conn, char *node_name);
void set_primary_last_seen(PGconn *conn); void set_primary_last_seen(PGconn *conn);
int get_primary_last_seen(PGconn *conn); int get_primary_last_seen(PGconn *conn);

View File

@@ -66,7 +66,6 @@ do_node_status(void)
PGconn *conn = NULL; PGconn *conn = NULL;
t_node_info node_info = T_NODE_INFO_INITIALIZER; t_node_info node_info = T_NODE_INFO_INITIALIZER;
char server_version[MAXLEN];
char cluster_size[MAXLEN]; char cluster_size[MAXLEN];
PQExpBufferData output; PQExpBufferData output;
@@ -80,6 +79,8 @@ do_node_status(void)
t_recovery_conf recovery_conf = T_RECOVERY_CONF_INITIALIZER; t_recovery_conf recovery_conf = T_RECOVERY_CONF_INITIALIZER;
char data_dir[MAXPGPATH] = ""; char data_dir[MAXPGPATH] = "";
int server_version_num = UNKNOWN_SERVER_VERSION_NUM;
char server_version_str[MAXVERSIONSTR] = "";
if (runtime_options.is_shutdown_cleanly == true) if (runtime_options.is_shutdown_cleanly == true)
{ {
@@ -90,7 +91,7 @@ do_node_status(void)
conn = establish_db_connection(config_file_options.conninfo, true); conn = establish_db_connection(config_file_options.conninfo, true);
strncpy(data_dir, config_file_options.data_directory, MAXPGPATH); strncpy(data_dir, config_file_options.data_directory, MAXPGPATH);
server_version_num = get_server_version(conn, NULL); server_version_num = get_server_version(conn, server_version_str);
/* check node exists */ /* check node exists */
@@ -101,18 +102,16 @@ do_node_status(void)
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
(void) get_server_version(conn, server_version);
if (get_cluster_size(conn, cluster_size) == false) if (get_cluster_size(conn, cluster_size) == false)
strncpy(cluster_size, _("unknown"), MAXLEN); strncpy(cluster_size, _("unknown"), MAXLEN);
recovery_type = get_recovery_type(conn); recovery_type = get_recovery_type(conn);
get_node_replication_stats(conn, server_version_num, &node_info); get_node_replication_stats(conn, &node_info);
key_value_list_set(&node_status, key_value_list_set(&node_status,
"PostgreSQL version", "PostgreSQL version",
server_version); server_version_str);
key_value_list_set(&node_status, key_value_list_set(&node_status,
"Total data size", "Total data size",
@@ -725,10 +724,8 @@ do_node_check(void)
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
server_version_num = get_server_version(conn, NULL);
/* add replication statistics to node record */ /* add replication statistics to node record */
get_node_replication_stats(conn, server_version_num, &node_info); get_node_replication_stats(conn, &node_info);
/* /*
* handle specific checks ====================== * handle specific checks ======================
@@ -1618,7 +1615,7 @@ do_node_check_slots(PGconn *conn, OutputMode mode, t_node_info *node_info, Check
initPQExpBuffer(&details); initPQExpBuffer(&details);
if (server_version_num < 90400) if (PQserverVersion(conn) < 90400)
{ {
appendPQExpBufferStr(&details, appendPQExpBufferStr(&details,
_("replication slots not available for this PostgreSQL version")); _("replication slots not available for this PostgreSQL version"));
@@ -1694,7 +1691,7 @@ do_node_check_missing_slots(PGconn *conn, OutputMode mode, t_node_info *node_inf
initPQExpBuffer(&details); initPQExpBuffer(&details);
if (server_version_num < 90400) if (PQserverVersion(conn) < 90400)
{ {
appendPQExpBufferStr(&details, appendPQExpBufferStr(&details,
_("replication slots not available for this PostgreSQL version")); _("replication slots not available for this PostgreSQL version"));
@@ -2005,7 +2002,6 @@ do_node_rejoin(void)
t_node_info primary_node_record = T_NODE_INFO_INITIALIZER; t_node_info primary_node_record = T_NODE_INFO_INITIALIZER;
bool success = true; bool success = true;
int server_version_num = UNKNOWN_SERVER_VERSION_NUM;
int follow_error_code = SUCCESS; int follow_error_code = SUCCESS;
/* check node is not actually running */ /* check node is not actually running */
@@ -2063,9 +2059,8 @@ do_node_rejoin(void)
upstream_conn = establish_db_connection_by_params(&source_conninfo, true); upstream_conn = establish_db_connection_by_params(&source_conninfo, true);
/* sanity checks for 9.3 */ /* sanity checks for 9.3 */
server_version_num = get_server_version(upstream_conn, NULL);
if (server_version_num < 90400) if (PQserverVersion(upstream_conn) < 90400)
check_93_config(); check_93_config();
if (get_primary_node_record(upstream_conn, &primary_node_record) == false) if (get_primary_node_record(upstream_conn, &primary_node_record) == false)

View File

@@ -1083,7 +1083,7 @@ _do_create_recovery_conf(void)
/* if not, if check one can and should be created */ /* if not, if check one can and should be created */
else else
{ {
get_node_replication_stats(upstream_conn, UNKNOWN_SERVER_VERSION_NUM, &upstream_node_record); get_node_replication_stats(upstream_conn, &upstream_node_record);
if (upstream_node_record.max_replication_slots > upstream_node_record.total_replication_slots) if (upstream_node_record.max_replication_slots > upstream_node_record.total_replication_slots)
{ {
@@ -2194,7 +2194,6 @@ do_standby_follow(void)
t_event_info event_info = T_EVENT_INFO_INITIALIZER; t_event_info event_info = T_EVENT_INFO_INITIALIZER;
int timer = 0; int timer = 0;
int server_version_num = UNKNOWN_SERVER_VERSION_NUM;
PQExpBufferData follow_output; PQExpBufferData follow_output;
bool success = false; bool success = false;
@@ -2221,9 +2220,7 @@ do_standby_follow(void)
check_recovery_type(local_conn); check_recovery_type(local_conn);
/* sanity-checks for 9.3 */ /* sanity-checks for 9.3 */
server_version_num = get_server_version(local_conn, NULL); if (PQserverVersion(local_conn) < 90400)
if (server_version_num < 90400)
check_93_config(); check_93_config();
/* /*
@@ -2577,7 +2574,7 @@ do_standby_follow_internal(PGconn *primary_conn, t_node_info *primary_node_recor
if (config_file_options.use_replication_slots) if (config_file_options.use_replication_slots)
{ {
int primary_server_version_num = get_server_version(primary_conn, NULL); int primary_server_version_num = PQserverVersion(primary_conn);
/* /*
* Here we add a sanity check for the "slot_name" field - it's possible * Here we add a sanity check for the "slot_name" field - it's possible
@@ -3202,7 +3199,7 @@ do_standby_switchover(void)
* populate local node record with current state of various replication-related * populate local node record with current state of various replication-related
* values, so we can check for sufficient walsenders and replication slots * values, so we can check for sufficient walsenders and replication slots
*/ */
get_node_replication_stats(local_conn, server_version_num, &local_node_record); get_node_replication_stats(local_conn, &local_node_record);
available_wal_senders = local_node_record.max_wal_senders - available_wal_senders = local_node_record.max_wal_senders -
local_node_record.attached_wal_receivers; local_node_record.attached_wal_receivers;

View File

@@ -2238,17 +2238,15 @@ create_repmgr_extension(PGconn *conn)
int int
check_server_version(PGconn *conn, char *server_type, bool exit_on_error, char *server_version_string) check_server_version(PGconn *conn, char *server_type, bool exit_on_error, char *server_version_string)
{ {
int conn_server_version_num = UNKNOWN_SERVER_VERSION_NUM; int conn_server_version_num = get_server_version(conn, server_version_string);
conn_server_version_num = get_server_version(conn, server_version_string);
if (conn_server_version_num < MIN_SUPPORTED_VERSION_NUM) if (conn_server_version_num < MIN_SUPPORTED_VERSION_NUM)
{ {
if (conn_server_version_num > 0) if (conn_server_version_num > 0)
log_error(_("%s requires %s to be PostgreSQL %s or later"), log_error(_("%s requires %s to be PostgreSQL %s or later"),
progname(), progname(),
server_type, server_type,
MIN_SUPPORTED_VERSION MIN_SUPPORTED_VERSION);
);
if (exit_on_error == true) if (exit_on_error == true)
{ {
@@ -2256,7 +2254,7 @@ check_server_version(PGconn *conn, char *server_type, bool exit_on_error, char *
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
return -1; return UNKNOWN_SERVER_VERSION_NUM;
} }
return conn_server_version_num; return conn_server_version_num;
@@ -3032,10 +3030,9 @@ bool
can_use_pg_rewind(PGconn *conn, const char *data_directory, PQExpBufferData *reason) can_use_pg_rewind(PGconn *conn, const char *data_directory, PQExpBufferData *reason)
{ {
bool can_use = true; bool can_use = true;
int server_version_num = get_server_version(conn, NULL);
/* wal_log_hints not available in 9.3, so just determine if data checksums enabled */ /* wal_log_hints not available in 9.3, so just determine if data checksums enabled */
if (server_version_num < 90400) if (PQserverVersion(conn) < 90400)
{ {
int data_checksum_version = get_data_checksum_version(data_directory); int data_checksum_version = get_data_checksum_version(data_directory);

View File

@@ -372,12 +372,6 @@ main(int argc, char **argv)
/* abort if local node not available at startup */ /* abort if local node not available at startup */
local_conn = establish_db_connection(config_file_options.conninfo, true); local_conn = establish_db_connection(config_file_options.conninfo, true);
/*
* store the server version number - we'll need this to generate
* version-dependent queries etc.
*/
server_version_num = get_server_version(local_conn, NULL);
/* /*
* sanity checks * sanity checks
* *