mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-16 02:23:49 +08:00
Check timescaledb extension version on a data node
Compare remote connection extension version with the one installed on the access node. Show a warning message if it differs. Check happens during add_data_node() call and after creating new data node connection.
This commit is contained in:
parent
0c0e6b1070
commit
55d205b09b
@ -26,7 +26,6 @@
|
||||
#include "catalog.h"
|
||||
#include "extension.h"
|
||||
#include "guc.h"
|
||||
#include "config.h"
|
||||
#include "extension_utils.c"
|
||||
#include "compat.h"
|
||||
|
||||
|
@ -12,5 +12,6 @@ install(
|
||||
timescaledb--mock-3--mock-4.sql
|
||||
timescaledb--mock-5--mock-6.sql
|
||||
timescaledb--mock-broken--mock-5.sql
|
||||
timescaledb--0.0.0.sql
|
||||
DESTINATION "${PG_SHAREDIR}/extension")
|
||||
endif (CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
|
3
test/sql/loader/timescaledb--0.0.0.sql
Normal file
3
test/sql/loader/timescaledb--0.0.0.sql
Normal file
@ -0,0 +1,3 @@
|
||||
-- This file and its contents are licensed under the Apache License 2.0.
|
||||
-- Please see the included NOTICE for copyright information and
|
||||
-- LICENSE-APACHE for a copy of the license.
|
@ -377,19 +377,13 @@ data_node_bootstrap_extension(const char *node_name, const char *host, int32 por
|
||||
const char *schema_name = ts_extension_schema_name();
|
||||
const char *schema_name_quoted = quote_identifier(schema_name);
|
||||
Oid schema_oid = get_namespace_oid(schema_name, true);
|
||||
bool extension_exists = false;
|
||||
bool extension_exists;
|
||||
|
||||
node_options = create_data_node_options(host, port, dbname, username);
|
||||
conn = remote_connection_open_with_options(node_name, node_options, false);
|
||||
|
||||
res = remote_connection_execf(conn,
|
||||
"SELECT 1 FROM pg_extension WHERE extname = %s",
|
||||
quote_literal_cstr(EXTENSION_NAME));
|
||||
|
||||
if (PQntuples(res) > 0)
|
||||
extension_exists = true;
|
||||
|
||||
remote_result_close(res);
|
||||
/* Ensure the extension exists and has correct version */
|
||||
extension_exists = remote_connection_check_extension(conn);
|
||||
|
||||
if (!extension_exists)
|
||||
{
|
||||
|
@ -242,3 +242,28 @@ validate_data_node_settings(void)
|
||||
max_prepared_xacts,
|
||||
MaxConnections)));
|
||||
}
|
||||
|
||||
int
|
||||
dist_util_version_compare(const char *lhs, const char *rhs)
|
||||
{
|
||||
unsigned int lhs_major, lhs_minor, lhs_patch;
|
||||
unsigned int rhs_major, rhs_minor, rhs_patch;
|
||||
|
||||
if (sscanf(lhs, "%u.%u.%u", &lhs_major, &lhs_minor, &lhs_patch) != 3)
|
||||
ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("invalid version %s", lhs)));
|
||||
|
||||
if (sscanf(rhs, "%u.%u.%u", &rhs_major, &rhs_minor, &rhs_patch) != 3)
|
||||
ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("invalid version %s", rhs)));
|
||||
|
||||
if (lhs_major == rhs_major)
|
||||
{
|
||||
if (lhs_minor == rhs_minor)
|
||||
{
|
||||
if (lhs_patch == rhs_patch)
|
||||
return 0;
|
||||
return (lhs_patch < rhs_patch) ? -1 : 1;
|
||||
}
|
||||
return (lhs_minor < rhs_minor) ? -1 : 1;
|
||||
}
|
||||
return (lhs_major < rhs_major) ? -1 : 1;
|
||||
}
|
||||
|
@ -31,5 +31,6 @@ bool dist_util_is_frontend_session(void);
|
||||
Datum dist_util_remote_hypertable_info(PG_FUNCTION_ARGS);
|
||||
|
||||
void validate_data_node_settings(void);
|
||||
int dist_util_version_compare(const char *lhs, const char *rhs);
|
||||
|
||||
#endif /* TIMESCALEDB_TSL_CHUNK_API_H */
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "guc.h"
|
||||
#include "utils.h"
|
||||
#include "dist_util.h"
|
||||
#include "errors.h"
|
||||
|
||||
/*
|
||||
* Connection library for TimescaleDB.
|
||||
@ -829,6 +830,46 @@ remote_result_query_ok(PGresult *res)
|
||||
return remote_result_ok(res, PGRES_TUPLES_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check timescaledb extension version on a data node.
|
||||
*
|
||||
* Compare remote connection extension version with the one installed
|
||||
* locally on the access node.
|
||||
*
|
||||
* Return false if extension is not found, true otherwise.
|
||||
*/
|
||||
bool
|
||||
remote_connection_check_extension(TSConnection *conn)
|
||||
{
|
||||
PGresult *res;
|
||||
int rc;
|
||||
|
||||
res = remote_connection_execf(conn,
|
||||
"SELECT extversion FROM pg_extension WHERE extname = %s",
|
||||
quote_literal_cstr(EXTENSION_NAME));
|
||||
|
||||
/* extension does not exists */
|
||||
if (PQntuples(res) == 0)
|
||||
{
|
||||
PQclear(res);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* compare extension version */
|
||||
rc = dist_util_version_compare(PQgetvalue(res, 0, 0), TIMESCALEDB_VERSION_MOD);
|
||||
if (rc < 0)
|
||||
ereport(WARNING,
|
||||
(errcode(ERRCODE_TS_DATA_NODE_INVALID_CONFIG),
|
||||
errmsg("data node \"%s\" has an outdated timescaledb extension version",
|
||||
NameStr(conn->node_name)),
|
||||
errdetail_internal("Access node version: %s, data node version: %s.",
|
||||
TIMESCALEDB_VERSION_MOD,
|
||||
PQgetvalue(res, 0, 0))));
|
||||
|
||||
PQclear(res);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure remote connection using current instance UUID.
|
||||
*
|
||||
@ -1033,12 +1074,19 @@ remote_connection_open_with_options(const char *node_name, List *connection_opti
|
||||
errmsg("could not configure remote connection to \"%s\"", node_name),
|
||||
errdetail_internal("%s", PQerrorMessage(conn->pg_conn))));
|
||||
|
||||
/* Inform remote node about instance UUID */
|
||||
if (set_dist_id && !remote_connection_set_peer_dist_id(conn))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION),
|
||||
errmsg("could not set distributed ID for \"%s\"", node_name),
|
||||
errdetail_internal("%s", PQerrorMessage(conn->pg_conn))));
|
||||
/* Check a data node extension version and show a warning
|
||||
* message if it differs */
|
||||
remote_connection_check_extension(conn);
|
||||
|
||||
if (set_dist_id)
|
||||
{
|
||||
/* Inform remote node about instance UUID */
|
||||
if (!remote_connection_set_peer_dist_id(conn))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION),
|
||||
errmsg("could not set distributed ID for \"%s\"", node_name),
|
||||
errdetail_internal("%s", PQerrorMessage(conn->pg_conn))));
|
||||
}
|
||||
}
|
||||
PG_CATCH();
|
||||
{
|
||||
|
@ -60,6 +60,7 @@ extern unsigned int remote_connection_get_cursor_number(void);
|
||||
extern void remote_connection_reset_cursor_number(void);
|
||||
extern unsigned int remote_connection_get_prep_stmt_number(void);
|
||||
extern bool remote_connection_configure(TSConnection *conn);
|
||||
extern bool remote_connection_check_extension(TSConnection *conn);
|
||||
extern bool remote_connection_cancel_query(TSConnection *conn);
|
||||
extern PGconn *remote_connection_get_pg_conn(TSConnection *conn);
|
||||
extern bool remote_connection_is_processing(TSConnection *conn);
|
||||
|
@ -1235,6 +1235,62 @@ WARNING: new data for hypertable "disttable_4" will be under-replicated due to
|
||||
SELECT * FROM add_data_node('data_node_6');
|
||||
ERROR: function add_data_node(unknown) does not exist at character 15
|
||||
\set ON_ERROR_STOP 1
|
||||
--
|
||||
-- Test timescale extension version check during add_data_node()
|
||||
-- and create_distributed_hypertable() calls.
|
||||
--
|
||||
-- Use mock extension and create basic function wrappers to
|
||||
-- establish connection to a data node.
|
||||
--
|
||||
RESET ROLE;
|
||||
DROP DATABASE data_node_1;
|
||||
CREATE DATABASE data_node_1 OWNER :ROLE_1;
|
||||
\c data_node_1
|
||||
CREATE SCHEMA _timescaledb_internal;
|
||||
GRANT ALL ON SCHEMA _timescaledb_internal TO :ROLE_1;
|
||||
CREATE FUNCTION _timescaledb_internal.set_dist_id(uuid UUID)
|
||||
RETURNS BOOL LANGUAGE PLPGSQL AS
|
||||
$BODY$
|
||||
BEGIN
|
||||
RETURN true;
|
||||
END
|
||||
$BODY$;
|
||||
CREATE FUNCTION _timescaledb_internal.set_peer_dist_id(uuid UUID)
|
||||
RETURNS BOOL LANGUAGE PLPGSQL AS
|
||||
$BODY$
|
||||
BEGIN
|
||||
RETURN true;
|
||||
END
|
||||
$BODY$;
|
||||
CREATE FUNCTION _timescaledb_internal.validate_as_data_node()
|
||||
RETURNS BOOL LANGUAGE PLPGSQL AS
|
||||
$BODY$
|
||||
BEGIN
|
||||
RETURN true;
|
||||
END
|
||||
$BODY$;
|
||||
CREATE EXTENSION timescaledb VERSION '0.0.0';
|
||||
\c :TEST_DBNAME :ROLE_SUPERUSER;
|
||||
SELECT * FROM add_data_node('data_node_1', 'localhost', database => 'data_node_1',
|
||||
if_not_exists => true);
|
||||
NOTICE: database "data_node_1" already exists on data node, not creating it
|
||||
WARNING: data node "data_node_1" has an outdated timescaledb extension version
|
||||
WARNING: data node "data_node_1" has an outdated timescaledb extension version
|
||||
WARNING: data node "data_node_1" has an outdated timescaledb extension version
|
||||
node_name | host | port | database | node_created | database_created | extension_created
|
||||
-------------+-----------+-------+-------------+--------------+------------------+-------------------
|
||||
data_node_1 | localhost | 15432 | data_node_1 | t | f | f
|
||||
(1 row)
|
||||
|
||||
GRANT USAGE ON FOREIGN SERVER data_node_1 TO :ROLE_1;
|
||||
SET ROLE :ROLE_1;
|
||||
CREATE TABLE test_disttable(time timestamptz);
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT * FROM create_distributed_hypertable('test_disttable', 'time');
|
||||
NOTICE: adding not-null constraint to column "time"
|
||||
WARNING: data node "data_node_1" has an outdated timescaledb extension version
|
||||
ERROR: [data_node_1]: function public.create_hypertable(unknown, time_column_name => unknown, associated_schema_name => unknown, associated_table_prefix => unknown, chunk_time_interval => bigint, chunk_sizing_func => unknown, chunk_target_size => unknown, if_not_exists => boolean, migrate_data => boolean, create_default_indexes => boolean, replication_factor => integer) does not exist
|
||||
\set ON_ERROR_STOP 1
|
||||
RESET ROLE;
|
||||
DROP DATABASE data_node_1;
|
||||
DROP DATABASE data_node_2;
|
||||
|
@ -61,7 +61,7 @@ ERROR: bad query error thrown from test
|
||||
SELECT * FROM test.get_connection_stats();
|
||||
connections_created | connections_closed | results_created | results_cleared
|
||||
---------------------+--------------------+-----------------+-----------------
|
||||
1 | 1 | 6 | 6
|
||||
1 | 1 | 7 | 7
|
||||
(1 row)
|
||||
|
||||
SELECT test.remote_connection_tests();
|
||||
|
@ -575,8 +575,62 @@ SELECT * FROM delete_data_node('data_node_5', force =>true);
|
||||
SELECT * FROM add_data_node('data_node_6');
|
||||
\set ON_ERROR_STOP 1
|
||||
|
||||
--
|
||||
-- Test timescale extension version check during add_data_node()
|
||||
-- and create_distributed_hypertable() calls.
|
||||
--
|
||||
-- Use mock extension and create basic function wrappers to
|
||||
-- establish connection to a data node.
|
||||
--
|
||||
RESET ROLE;
|
||||
DROP DATABASE data_node_1;
|
||||
CREATE DATABASE data_node_1 OWNER :ROLE_1;
|
||||
|
||||
\c data_node_1
|
||||
CREATE SCHEMA _timescaledb_internal;
|
||||
GRANT ALL ON SCHEMA _timescaledb_internal TO :ROLE_1;
|
||||
|
||||
CREATE FUNCTION _timescaledb_internal.set_dist_id(uuid UUID)
|
||||
RETURNS BOOL LANGUAGE PLPGSQL AS
|
||||
$BODY$
|
||||
BEGIN
|
||||
RETURN true;
|
||||
END
|
||||
$BODY$;
|
||||
|
||||
CREATE FUNCTION _timescaledb_internal.set_peer_dist_id(uuid UUID)
|
||||
RETURNS BOOL LANGUAGE PLPGSQL AS
|
||||
$BODY$
|
||||
BEGIN
|
||||
RETURN true;
|
||||
END
|
||||
$BODY$;
|
||||
|
||||
CREATE FUNCTION _timescaledb_internal.validate_as_data_node()
|
||||
RETURNS BOOL LANGUAGE PLPGSQL AS
|
||||
$BODY$
|
||||
BEGIN
|
||||
RETURN true;
|
||||
END
|
||||
$BODY$;
|
||||
|
||||
CREATE EXTENSION timescaledb VERSION '0.0.0';
|
||||
|
||||
\c :TEST_DBNAME :ROLE_SUPERUSER;
|
||||
|
||||
SELECT * FROM add_data_node('data_node_1', 'localhost', database => 'data_node_1',
|
||||
if_not_exists => true);
|
||||
|
||||
GRANT USAGE ON FOREIGN SERVER data_node_1 TO :ROLE_1;
|
||||
|
||||
SET ROLE :ROLE_1;
|
||||
CREATE TABLE test_disttable(time timestamptz);
|
||||
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT * FROM create_distributed_hypertable('test_disttable', 'time');
|
||||
\set ON_ERROR_STOP 1
|
||||
|
||||
RESET ROLE;
|
||||
DROP DATABASE data_node_1;
|
||||
DROP DATABASE data_node_2;
|
||||
DROP DATABASE data_node_3;
|
||||
|
Loading…
x
Reference in New Issue
Block a user