mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-16 02:23:49 +08:00
Add distributed_exec() function
This function allows users to execute a SQL query on a list of data nodes. The purpose is to provide users a way to, e.g., create roles on data nodes. The current implementation is quite straightforward. Just execute any provided query on a list of data nodes. The query will execute with the current user role. The function does not return or print any result values. In case of error, it will print the data node name and a related error message.
This commit is contained in:
parent
334604edc7
commit
c8563b2d46
@ -200,3 +200,8 @@ AS '@MODULE_PATHNAME@', 'ts_data_node_block_new_chunks' LANGUAGE C VOLATILE;
|
||||
-- allow chunks for all distributed hypertables
|
||||
CREATE OR REPLACE FUNCTION allow_new_chunks(data_node_name NAME, hypertable REGCLASS = NULL) RETURNS INTEGER
|
||||
AS '@MODULE_PATHNAME@', 'ts_data_node_allow_new_chunks' LANGUAGE C VOLATILE;
|
||||
|
||||
-- Execute query on a specified list of data nodes. By default node_list is NULL, which means
|
||||
-- to execute the query on every data node
|
||||
CREATE OR REPLACE FUNCTION distributed_exec(query TEXT, node_list name[] = NULL) RETURNS VOID
|
||||
AS '@MODULE_PATHNAME@', 'ts_distributed_exec' LANGUAGE C VOLATILE;
|
||||
|
@ -63,6 +63,7 @@ TS_FUNCTION_INFO_V1(ts_dist_remove_id);
|
||||
TS_FUNCTION_INFO_V1(ts_dist_set_peer_id);
|
||||
TS_FUNCTION_INFO_V1(ts_dist_remote_hypertable_info);
|
||||
TS_FUNCTION_INFO_V1(ts_dist_validate_as_data_node);
|
||||
TS_FUNCTION_INFO_V1(ts_distributed_exec);
|
||||
|
||||
Datum
|
||||
ts_add_drop_chunks_policy(PG_FUNCTION_ARGS)
|
||||
@ -234,6 +235,13 @@ ts_dist_validate_as_data_node(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
Datum
|
||||
ts_distributed_exec(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ts_cm_functions->distributed_exec(fcinfo);
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
/*
|
||||
* stub function to trigger aggregate util functions.
|
||||
*/
|
||||
@ -630,6 +638,7 @@ TSDLLEXPORT CrossModuleFunctions ts_cm_functions_default = {
|
||||
.data_node_ping = error_no_default_fn_pg_community,
|
||||
.detach_data_node = error_no_default_fn_pg_community,
|
||||
.data_node_set_block_new_chunks = data_node_set_block_new_chunks_default,
|
||||
.distributed_exec = error_no_default_fn_pg_community,
|
||||
.set_chunk_default_data_node = error_no_default_fn_pg_community,
|
||||
.show_chunk = error_no_default_fn_pg_community,
|
||||
.create_chunk = error_no_default_fn_pg_community,
|
||||
|
@ -145,6 +145,7 @@ typedef struct CrossModuleFunctions
|
||||
Oid newer_than_type, bool cascade,
|
||||
bool cascades_to_materializations, bool verbose,
|
||||
List *data_node_oids);
|
||||
PGFunction distributed_exec;
|
||||
} CrossModuleFunctions;
|
||||
|
||||
extern TSDLLEXPORT CrossModuleFunctions *ts_cm_functions;
|
||||
|
@ -35,6 +35,7 @@ ORDER BY proname;
|
||||
detach_data_node
|
||||
detach_tablespace
|
||||
detach_tablespaces
|
||||
distributed_exec
|
||||
drop_chunks
|
||||
first
|
||||
get_telemetry_report
|
||||
@ -65,5 +66,5 @@ ORDER BY proname;
|
||||
timescaledb_fdw_validator
|
||||
timescaledb_post_restore
|
||||
timescaledb_pre_restore
|
||||
(51 rows)
|
||||
(52 rows)
|
||||
|
||||
|
@ -58,7 +58,7 @@ if [[ ! -f ${TEST_OUTPUT_DIR}/.pg_init ]]; then
|
||||
SET client_min_messages=ERROR;
|
||||
ALTER USER ${TEST_ROLE_SUPERUSER} WITH SUPERUSER;
|
||||
ALTER USER ${TEST_ROLE_CLUSTER_SUPERUSER} WITH SUPERUSER;
|
||||
ALTER USER ${TEST_ROLE_1} WITH CREATEDB;
|
||||
ALTER USER ${TEST_ROLE_1} WITH CREATEDB CREATEROLE;
|
||||
ALTER USER ${TEST_ROLE_2} WITH CREATEDB;
|
||||
ALTER USER ${TEST_ROLE_3} WITH CREATEDB PASSWORD '${TEST_ROLE_3_PASS}';
|
||||
EOF
|
||||
|
@ -555,7 +555,7 @@ data_node_add_internal(PG_FUNCTION_ARGS, bool set_distid)
|
||||
bool database_created = false;
|
||||
bool extension_created = false;
|
||||
|
||||
if (set_distid && dist_util_membership() == DIST_MEMBER_BACKEND)
|
||||
if (set_distid && dist_util_membership() == DIST_MEMBER_DATA_NODE)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_TS_DATA_NODE_ASSIGNMENT_ALREADY_EXISTS),
|
||||
(errmsg("unable to assign data nodes from an existing distributed database"))));
|
||||
@ -603,7 +603,7 @@ data_node_add_internal(PG_FUNCTION_ARGS, bool set_distid)
|
||||
|
||||
if (set_distid)
|
||||
{
|
||||
if (dist_util_membership() != DIST_MEMBER_FRONTEND)
|
||||
if (dist_util_membership() != DIST_MEMBER_ACCESS_NODE)
|
||||
dist_util_set_as_frontend();
|
||||
|
||||
add_distributed_id_to_data_node(node_name,
|
||||
|
@ -56,9 +56,9 @@ dist_util_membership(void)
|
||||
if (isnull)
|
||||
return DIST_MEMBER_NONE;
|
||||
else if (uuid_matches(dist_id, ts_telemetry_metadata_get_uuid()))
|
||||
return DIST_MEMBER_FRONTEND;
|
||||
return DIST_MEMBER_ACCESS_NODE;
|
||||
else
|
||||
return DIST_MEMBER_BACKEND;
|
||||
return DIST_MEMBER_DATA_NODE;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -11,9 +11,9 @@
|
||||
|
||||
typedef enum DistUtilMembershipStatus
|
||||
{
|
||||
DIST_MEMBER_NONE, /* Database doesn't belong to a distributed database */
|
||||
DIST_MEMBER_BACKEND, /* Database is a backend node */
|
||||
DIST_MEMBER_FRONTEND /* Database is a frontend node */
|
||||
DIST_MEMBER_NONE, /* Database doesn't belong to a distributed database */
|
||||
DIST_MEMBER_DATA_NODE, /* Database is a backend node */
|
||||
DIST_MEMBER_ACCESS_NODE /* Database is a frontend node */
|
||||
} DistUtilMembershipStatus;
|
||||
|
||||
DistUtilMembershipStatus dist_util_membership(void);
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include "remote/txn_id.h"
|
||||
#include "remote/txn_resolve.h"
|
||||
#include "remote/dist_copy.h"
|
||||
#include "remote/dist_commands.h"
|
||||
#include "process_utility.h"
|
||||
#include "dist_util.h"
|
||||
#include "remote/connection.h"
|
||||
@ -256,6 +257,7 @@ CrossModuleFunctions tsl_cm_functions = {
|
||||
.remove_from_distributed_db = NULL,
|
||||
.remote_hypertable_info = error_not_supported_default_fn,
|
||||
.validate_as_data_node = NULL,
|
||||
.distributed_exec = error_not_supported_default_fn,
|
||||
#else
|
||||
.add_data_node = data_node_add,
|
||||
.delete_data_node = data_node_delete,
|
||||
@ -287,6 +289,7 @@ CrossModuleFunctions tsl_cm_functions = {
|
||||
.remote_hypertable_info = dist_util_remote_hypertable_info,
|
||||
.validate_as_data_node = validate_data_node_settings,
|
||||
.drop_chunks_on_data_nodes = chunk_drop_remote_chunks,
|
||||
.distributed_exec = ts_dist_cmd_exec,
|
||||
#endif
|
||||
.cache_syscache_invalidate = cache_syscache_invalidate,
|
||||
};
|
||||
|
@ -4,6 +4,9 @@
|
||||
* LICENSE-TIMESCALE for a copy of the license.
|
||||
*/
|
||||
#include <postgres.h>
|
||||
#include <utils/builtins.h>
|
||||
#include <utils/guc.h>
|
||||
#include <catalog/namespace.h>
|
||||
|
||||
#include <libpq-fe.h>
|
||||
|
||||
@ -11,6 +14,7 @@
|
||||
#include "remote/dist_txn.h"
|
||||
#include "remote/connection_cache.h"
|
||||
#include "data_node.h"
|
||||
#include "dist_util.h"
|
||||
#include "miscadmin.h"
|
||||
|
||||
typedef struct DistPreparedStmt
|
||||
@ -235,3 +239,32 @@ ts_dist_cmd_close_prepared_command(PreparedDistCmd *command)
|
||||
|
||||
list_free_deep(command);
|
||||
}
|
||||
|
||||
Datum
|
||||
ts_dist_cmd_exec(PG_FUNCTION_ARGS)
|
||||
{
|
||||
const char *query = TextDatumGetCString(PG_GETARG_DATUM(0));
|
||||
ArrayType *data_nodes = PG_ARGISNULL(1) ? NULL : PG_GETARG_ARRAYTYPE_P(1);
|
||||
DistCmdResult *result;
|
||||
List *data_node_list;
|
||||
const char *search_path;
|
||||
|
||||
if (dist_util_membership() != DIST_MEMBER_ACCESS_NODE)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("function must be run on the access node only")));
|
||||
|
||||
if (data_nodes == NULL)
|
||||
data_node_list = data_node_get_node_name_list();
|
||||
else
|
||||
data_node_list = data_node_array_to_node_name_list(data_nodes);
|
||||
|
||||
search_path = GetConfigOption("search_path", false, false);
|
||||
result = ts_dist_cmd_invoke_on_data_nodes_using_search_path(query, search_path, data_node_list);
|
||||
if (result)
|
||||
ts_dist_cmd_close_response(result);
|
||||
|
||||
list_free(data_node_list);
|
||||
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
@ -35,4 +35,6 @@ extern DistCmdResult *ts_dist_cmd_invoke_prepared_command(PreparedDistCmd *comma
|
||||
|
||||
extern void ts_dist_cmd_close_prepared_command(PreparedDistCmd *command);
|
||||
|
||||
extern Datum ts_dist_cmd_exec(PG_FUNCTION_ARGS);
|
||||
|
||||
#endif
|
||||
|
@ -2,38 +2,42 @@
|
||||
-- Please see the included NOTICE for copyright information and
|
||||
-- LICENSE-TIMESCALE for a copy of the license.
|
||||
\c :TEST_DBNAME :ROLE_SUPERUSER
|
||||
-- Support for execute_sql_and_filter_server_name_on_error()
|
||||
\unset ECHO
|
||||
psql:include/remote_exec.sql:5: NOTICE: schema "test" already exists, skipping
|
||||
psql:include/filter_exec.sql:5: NOTICE: schema "test" already exists, skipping
|
||||
SET ROLE :ROLE_1;
|
||||
SELECT * FROM add_data_node('data_node1',
|
||||
database => 'data_node1',
|
||||
SELECT * FROM add_data_node('data_node_1',
|
||||
database => 'data_node_1',
|
||||
bootstrap_user => :'ROLE_CLUSTER_SUPERUSER');
|
||||
node_name | host | port | database | node_created | database_created | extension_created
|
||||
------------+-----------+-------+------------+--------------+------------------+-------------------
|
||||
data_node1 | localhost | 15432 | data_node1 | t | t | t
|
||||
node_name | host | port | database | node_created | database_created | extension_created
|
||||
-------------+-----------+-------+-------------+--------------+------------------+-------------------
|
||||
data_node_1 | localhost | 15432 | data_node_1 | t | t | t
|
||||
(1 row)
|
||||
|
||||
SELECT * FROM add_data_node('data_node2',
|
||||
database => 'data_node2',
|
||||
SELECT * FROM add_data_node('data_node_2',
|
||||
database => 'data_node_2',
|
||||
bootstrap_user => :'ROLE_CLUSTER_SUPERUSER');
|
||||
node_name | host | port | database | node_created | database_created | extension_created
|
||||
------------+-----------+-------+------------+--------------+------------------+-------------------
|
||||
data_node2 | localhost | 15432 | data_node2 | t | t | t
|
||||
node_name | host | port | database | node_created | database_created | extension_created
|
||||
-------------+-----------+-------+-------------+--------------+------------------+-------------------
|
||||
data_node_2 | localhost | 15432 | data_node_2 | t | t | t
|
||||
(1 row)
|
||||
|
||||
SELECT * FROM add_data_node('data_node3',
|
||||
database => 'data_node3',
|
||||
SELECT * FROM add_data_node('data_node_3',
|
||||
database => 'data_node_3',
|
||||
bootstrap_user => :'ROLE_CLUSTER_SUPERUSER');
|
||||
node_name | host | port | database | node_created | database_created | extension_created
|
||||
------------+-----------+-------+------------+--------------+------------------+-------------------
|
||||
data_node3 | localhost | 15432 | data_node3 | t | t | t
|
||||
node_name | host | port | database | node_created | database_created | extension_created
|
||||
-------------+-----------+-------+-------------+--------------+------------------+-------------------
|
||||
data_node_3 | localhost | 15432 | data_node_3 | t | t | t
|
||||
(1 row)
|
||||
|
||||
\des+
|
||||
List of foreign servers
|
||||
Name | Owner | Foreign-data wrapper | Access privileges | Type | Version | FDW options | Description
|
||||
------------+-------------+----------------------+-------------------+------+---------+-------------------------------------------------------+-------------
|
||||
data_node1 | test_role_1 | timescaledb_fdw | | | | (host 'localhost', port '15432', dbname 'data_node1') |
|
||||
data_node2 | test_role_1 | timescaledb_fdw | | | | (host 'localhost', port '15432', dbname 'data_node2') |
|
||||
data_node3 | test_role_1 | timescaledb_fdw | | | | (host 'localhost', port '15432', dbname 'data_node3') |
|
||||
List of foreign servers
|
||||
Name | Owner | Foreign-data wrapper | Access privileges | Type | Version | FDW options | Description
|
||||
-------------+-------------+----------------------+-------------------+------+---------+--------------------------------------------------------+-------------
|
||||
data_node_1 | test_role_1 | timescaledb_fdw | | | | (host 'localhost', port '15432', dbname 'data_node_1') |
|
||||
data_node_2 | test_role_1 | timescaledb_fdw | | | | (host 'localhost', port '15432', dbname 'data_node_2') |
|
||||
data_node_3 | test_role_1 | timescaledb_fdw | | | | (host 'localhost', port '15432', dbname 'data_node_3') |
|
||||
(3 rows)
|
||||
|
||||
RESET ROLE;
|
||||
@ -47,19 +51,19 @@ AS :TSL_MODULE_PATHNAME, 'tsl_invoke_faulty_distributed_command'
|
||||
LANGUAGE C STRICT;
|
||||
SET ROLE :ROLE_1;
|
||||
SELECT _timescaledb_internal.invoke_distributed_commands();
|
||||
INFO: data_node1 result: PGRES_COMMAND_OK
|
||||
INFO: data_node2 result: PGRES_COMMAND_OK
|
||||
INFO: data_node3 result: PGRES_COMMAND_OK
|
||||
INFO: data_node1 result: PGRES_COMMAND_OK
|
||||
INFO: data_node2 result: PGRES_COMMAND_OK
|
||||
INFO: data_node1 result: PGRES_COMMAND_OK
|
||||
INFO: data_node2 result: PGRES_COMMAND_OK
|
||||
INFO: data_node_1 result: PGRES_COMMAND_OK
|
||||
INFO: data_node_2 result: PGRES_COMMAND_OK
|
||||
INFO: data_node_3 result: PGRES_COMMAND_OK
|
||||
INFO: data_node_1 result: PGRES_COMMAND_OK
|
||||
INFO: data_node_2 result: PGRES_COMMAND_OK
|
||||
INFO: data_node_1 result: PGRES_COMMAND_OK
|
||||
INFO: data_node_2 result: PGRES_COMMAND_OK
|
||||
invoke_distributed_commands
|
||||
-----------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
\c data_node1
|
||||
\c data_node_1
|
||||
\dt
|
||||
List of relations
|
||||
Schema | Name | Type | Owner
|
||||
@ -74,7 +78,7 @@ SELECT * FROM disttable1;
|
||||
Sat Sep 18 00:00:00 1976 PDT | 47 | 103.4
|
||||
(1 row)
|
||||
|
||||
\c data_node2
|
||||
\c data_node_2
|
||||
\dt
|
||||
List of relations
|
||||
Schema | Name | Type | Owner
|
||||
@ -89,7 +93,7 @@ SELECT * FROM disttable1;
|
||||
Sat Sep 18 00:00:00 1976 PDT | 47 | 103.4
|
||||
(1 row)
|
||||
|
||||
\c data_node3
|
||||
\c data_node_3
|
||||
\dt
|
||||
List of relations
|
||||
Schema | Name | Type | Owner
|
||||
@ -107,15 +111,15 @@ SET ROLE :ROLE_1;
|
||||
-- Verify failed insert command gets fully rolled back
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT _timescaledb_internal.invoke_faulty_distributed_command();
|
||||
ERROR: [data_node3]: relation "public.disttable2" does not exist
|
||||
ERROR: [data_node_3]: relation "public.disttable2" does not exist
|
||||
\set ON_ERROR_STOP 1
|
||||
\c data_node1
|
||||
\c data_node_1
|
||||
SELECT * from disttable2;
|
||||
time | device | temp
|
||||
------+--------+------
|
||||
(0 rows)
|
||||
|
||||
\c data_node2
|
||||
\c data_node_2
|
||||
SELECT * from disttable2;
|
||||
time | device | temp
|
||||
------+--------+------
|
||||
@ -131,7 +135,7 @@ psql:include/remote_exec.sql:5: NOTICE: schema "test" already exists, skipping
|
||||
CREATE OR REPLACE FUNCTION is_frontend_session()
|
||||
RETURNS BOOL
|
||||
AS :TSL_MODULE_PATHNAME, 'test_is_frontend_session' LANGUAGE C;
|
||||
\c data_node1
|
||||
\c data_node_1
|
||||
CREATE OR REPLACE FUNCTION is_frontend_session()
|
||||
RETURNS BOOL
|
||||
AS :TSL_MODULE_PATHNAME, 'test_is_frontend_session' LANGUAGE C;
|
||||
@ -141,7 +145,7 @@ SELECT is_frontend_session();
|
||||
f
|
||||
(1 row)
|
||||
|
||||
\c data_node2
|
||||
\c data_node_2
|
||||
CREATE OR REPLACE FUNCTION is_frontend_session()
|
||||
RETURNS BOOL
|
||||
AS :TSL_MODULE_PATHNAME, 'test_is_frontend_session' LANGUAGE C;
|
||||
@ -151,7 +155,7 @@ SELECT is_frontend_session();
|
||||
f
|
||||
(1 row)
|
||||
|
||||
\c data_node3
|
||||
\c data_node_3
|
||||
CREATE OR REPLACE FUNCTION is_frontend_session()
|
||||
RETURNS BOOL
|
||||
AS :TSL_MODULE_PATHNAME, 'test_is_frontend_session' LANGUAGE C;
|
||||
@ -171,31 +175,31 @@ SELECT is_frontend_session();
|
||||
|
||||
-- Ensure peer dist id is already set and can be set only once
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT * FROM test.remote_exec('{data_node1}', $$ SELECT * FROM _timescaledb_internal.set_peer_dist_id('77348176-09da-4a80-bc78-e31bdf5e63ec'); $$);
|
||||
NOTICE: [data_node1]: SELECT * FROM _timescaledb_internal.set_peer_dist_id('77348176-09da-4a80-bc78-e31bdf5e63ec')
|
||||
ERROR: [data_node1]: distributed peer ID already set
|
||||
SELECT * FROM test.remote_exec('{data_node_1}', $$ SELECT * FROM _timescaledb_internal.set_peer_dist_id('77348176-09da-4a80-bc78-e31bdf5e63ec'); $$);
|
||||
NOTICE: [data_node_1]: SELECT * FROM _timescaledb_internal.set_peer_dist_id('77348176-09da-4a80-bc78-e31bdf5e63ec')
|
||||
ERROR: [data_node_1]: distributed peer ID already set
|
||||
\set ON_ERROR_STOP 1
|
||||
-- Repeat is_frontend_session() test again, but this time using connections openned from frontend
|
||||
-- to backend nodes. Must return true.
|
||||
SELECT * FROM test.remote_exec(NULL, $$ SELECT is_frontend_session(); $$);
|
||||
NOTICE: [data_node1]: SELECT is_frontend_session()
|
||||
NOTICE: [data_node1]:
|
||||
NOTICE: [data_node_1]: SELECT is_frontend_session()
|
||||
NOTICE: [data_node_1]:
|
||||
is_frontend_session
|
||||
-------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
|
||||
NOTICE: [data_node2]: SELECT is_frontend_session()
|
||||
NOTICE: [data_node2]:
|
||||
NOTICE: [data_node_2]: SELECT is_frontend_session()
|
||||
NOTICE: [data_node_2]:
|
||||
is_frontend_session
|
||||
-------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
|
||||
NOTICE: [data_node3]: SELECT is_frontend_session()
|
||||
NOTICE: [data_node3]:
|
||||
NOTICE: [data_node_3]: SELECT is_frontend_session()
|
||||
NOTICE: [data_node_3]:
|
||||
is_frontend_session
|
||||
-------------------
|
||||
t
|
||||
@ -207,7 +211,120 @@ t
|
||||
|
||||
(1 row)
|
||||
|
||||
-- Test distributed_exec()
|
||||
-- Make sure dist session is properly set
|
||||
SELECT * FROM distributed_exec('DO $$ BEGIN ASSERT(SELECT is_frontend_session()) = true; END; $$;');
|
||||
distributed_exec
|
||||
------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
-- Test creating and dropping a table
|
||||
SELECT * FROM distributed_exec('CREATE TABLE dist_test (id int)');
|
||||
distributed_exec
|
||||
------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT * FROM distributed_exec('INSERT INTO dist_test values (7)');
|
||||
distributed_exec
|
||||
------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT * FROM test.remote_exec(NULL, $$ SELECT * from dist_test; $$);
|
||||
NOTICE: [data_node_1]: SELECT * from dist_test
|
||||
NOTICE: [data_node_1]:
|
||||
id
|
||||
--
|
||||
7
|
||||
(1 row)
|
||||
|
||||
|
||||
NOTICE: [data_node_2]: SELECT * from dist_test
|
||||
NOTICE: [data_node_2]:
|
||||
id
|
||||
--
|
||||
7
|
||||
(1 row)
|
||||
|
||||
|
||||
NOTICE: [data_node_3]: SELECT * from dist_test
|
||||
NOTICE: [data_node_3]:
|
||||
id
|
||||
--
|
||||
7
|
||||
(1 row)
|
||||
|
||||
|
||||
remote_exec
|
||||
-------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT * FROM distributed_exec('DROP TABLE dist_test');
|
||||
distributed_exec
|
||||
------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT * FROM distributed_exec('INSERT INTO dist_test VALUES (8)', '{data_node_1}');
|
||||
ERROR: [data_node_1]: relation "dist_test" does not exist
|
||||
\set ON_ERROR_STOP 1
|
||||
-- Test creating and dropping a role
|
||||
CREATE ROLE dist_test_role;
|
||||
-- Expect this to be an error, since data nodes are created on the same instance
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT test.execute_sql_and_filter_data_node_name_on_error($$
|
||||
SELECT * FROM distributed_exec('CREATE ROLE dist_test_role');
|
||||
$$);
|
||||
ERROR: [data_node_x]: role "dist_test_role" already exists
|
||||
\set ON_ERROR_STOP 1
|
||||
SELECT * FROM test.remote_exec(NULL, $$ SELECT true from pg_catalog.pg_roles WHERE rolname = 'dist_test_role'; $$);
|
||||
NOTICE: [data_node_1]: SELECT true from pg_catalog.pg_roles WHERE rolname = 'dist_test_role'
|
||||
NOTICE: [data_node_1]:
|
||||
bool
|
||||
----
|
||||
t
|
||||
(1 row)
|
||||
|
||||
|
||||
NOTICE: [data_node_2]: SELECT true from pg_catalog.pg_roles WHERE rolname = 'dist_test_role'
|
||||
NOTICE: [data_node_2]:
|
||||
bool
|
||||
----
|
||||
t
|
||||
(1 row)
|
||||
|
||||
|
||||
NOTICE: [data_node_3]: SELECT true from pg_catalog.pg_roles WHERE rolname = 'dist_test_role'
|
||||
NOTICE: [data_node_3]:
|
||||
bool
|
||||
----
|
||||
t
|
||||
(1 row)
|
||||
|
||||
|
||||
remote_exec
|
||||
-------------
|
||||
|
||||
(1 row)
|
||||
|
||||
DROP ROLE DIST_TEST_ROLE;
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT test.execute_sql_and_filter_data_node_name_on_error($$
|
||||
SELECT * FROM distributed_exec('DROP ROLE dist_test_role');
|
||||
$$);
|
||||
ERROR: [data_node_x]: role "dist_test_role" does not exist
|
||||
\set ON_ERROR_STOP 1
|
||||
-- Do not allow to run distributed_exec() on a data nodes
|
||||
\c data_node_1
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT * FROM distributed_exec('SELECT 1');
|
||||
ERROR: function must be run on the access node only
|
||||
\set ON_ERROR_STOP 1
|
||||
\c :TEST_DBNAME :ROLE_SUPERUSER
|
||||
DROP DATABASE data_node1;
|
||||
DROP DATABASE data_node2;
|
||||
DROP DATABASE data_node3;
|
||||
DROP DATABASE data_node_1;
|
||||
DROP DATABASE data_node_2;
|
||||
DROP DATABASE data_node_3;
|
||||
|
@ -3,16 +3,25 @@
|
||||
-- LICENSE-TIMESCALE for a copy of the license.
|
||||
|
||||
\c :TEST_DBNAME :ROLE_SUPERUSER
|
||||
|
||||
-- Support for execute_sql_and_filter_server_name_on_error()
|
||||
\unset ECHO
|
||||
\o /dev/null
|
||||
\ir include/remote_exec.sql
|
||||
\ir include/filter_exec.sql
|
||||
\o
|
||||
\set ECHO all
|
||||
|
||||
SET ROLE :ROLE_1;
|
||||
|
||||
SELECT * FROM add_data_node('data_node1',
|
||||
database => 'data_node1',
|
||||
SELECT * FROM add_data_node('data_node_1',
|
||||
database => 'data_node_1',
|
||||
bootstrap_user => :'ROLE_CLUSTER_SUPERUSER');
|
||||
SELECT * FROM add_data_node('data_node2',
|
||||
database => 'data_node2',
|
||||
SELECT * FROM add_data_node('data_node_2',
|
||||
database => 'data_node_2',
|
||||
bootstrap_user => :'ROLE_CLUSTER_SUPERUSER');
|
||||
SELECT * FROM add_data_node('data_node3',
|
||||
database => 'data_node3',
|
||||
SELECT * FROM add_data_node('data_node_3',
|
||||
database => 'data_node_3',
|
||||
bootstrap_user => :'ROLE_CLUSTER_SUPERUSER');
|
||||
|
||||
\des+
|
||||
@ -31,13 +40,13 @@ SET ROLE :ROLE_1;
|
||||
|
||||
SELECT _timescaledb_internal.invoke_distributed_commands();
|
||||
|
||||
\c data_node1
|
||||
\c data_node_1
|
||||
\dt
|
||||
SELECT * FROM disttable1;
|
||||
\c data_node2
|
||||
\c data_node_2
|
||||
\dt
|
||||
SELECT * FROM disttable1;
|
||||
\c data_node3
|
||||
\c data_node_3
|
||||
\dt
|
||||
SELECT * FROM disttable1;
|
||||
\c :TEST_DBNAME :ROLE_SUPERUSER
|
||||
@ -48,9 +57,9 @@ SET ROLE :ROLE_1;
|
||||
SELECT _timescaledb_internal.invoke_faulty_distributed_command();
|
||||
\set ON_ERROR_STOP 1
|
||||
|
||||
\c data_node1
|
||||
\c data_node_1
|
||||
SELECT * from disttable2;
|
||||
\c data_node2
|
||||
\c data_node_2
|
||||
SELECT * from disttable2;
|
||||
|
||||
-- Test connection session identity
|
||||
@ -68,19 +77,19 @@ CREATE OR REPLACE FUNCTION is_frontend_session()
|
||||
RETURNS BOOL
|
||||
AS :TSL_MODULE_PATHNAME, 'test_is_frontend_session' LANGUAGE C;
|
||||
|
||||
\c data_node1
|
||||
\c data_node_1
|
||||
CREATE OR REPLACE FUNCTION is_frontend_session()
|
||||
RETURNS BOOL
|
||||
AS :TSL_MODULE_PATHNAME, 'test_is_frontend_session' LANGUAGE C;
|
||||
SELECT is_frontend_session();
|
||||
|
||||
\c data_node2
|
||||
\c data_node_2
|
||||
CREATE OR REPLACE FUNCTION is_frontend_session()
|
||||
RETURNS BOOL
|
||||
AS :TSL_MODULE_PATHNAME, 'test_is_frontend_session' LANGUAGE C;
|
||||
SELECT is_frontend_session();
|
||||
|
||||
\c data_node3
|
||||
\c data_node_3
|
||||
CREATE OR REPLACE FUNCTION is_frontend_session()
|
||||
RETURNS BOOL
|
||||
AS :TSL_MODULE_PATHNAME, 'test_is_frontend_session' LANGUAGE C;
|
||||
@ -92,14 +101,50 @@ SELECT is_frontend_session();
|
||||
|
||||
-- Ensure peer dist id is already set and can be set only once
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT * FROM test.remote_exec('{data_node1}', $$ SELECT * FROM _timescaledb_internal.set_peer_dist_id('77348176-09da-4a80-bc78-e31bdf5e63ec'); $$);
|
||||
SELECT * FROM test.remote_exec('{data_node_1}', $$ SELECT * FROM _timescaledb_internal.set_peer_dist_id('77348176-09da-4a80-bc78-e31bdf5e63ec'); $$);
|
||||
\set ON_ERROR_STOP 1
|
||||
|
||||
-- Repeat is_frontend_session() test again, but this time using connections openned from frontend
|
||||
-- to backend nodes. Must return true.
|
||||
SELECT * FROM test.remote_exec(NULL, $$ SELECT is_frontend_session(); $$);
|
||||
|
||||
-- Test distributed_exec()
|
||||
|
||||
-- Make sure dist session is properly set
|
||||
SELECT * FROM distributed_exec('DO $$ BEGIN ASSERT(SELECT is_frontend_session()) = true; END; $$;');
|
||||
|
||||
-- Test creating and dropping a table
|
||||
SELECT * FROM distributed_exec('CREATE TABLE dist_test (id int)');
|
||||
SELECT * FROM distributed_exec('INSERT INTO dist_test values (7)');
|
||||
SELECT * FROM test.remote_exec(NULL, $$ SELECT * from dist_test; $$);
|
||||
SELECT * FROM distributed_exec('DROP TABLE dist_test');
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT * FROM distributed_exec('INSERT INTO dist_test VALUES (8)', '{data_node_1}');
|
||||
\set ON_ERROR_STOP 1
|
||||
|
||||
-- Test creating and dropping a role
|
||||
CREATE ROLE dist_test_role;
|
||||
-- Expect this to be an error, since data nodes are created on the same instance
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT test.execute_sql_and_filter_data_node_name_on_error($$
|
||||
SELECT * FROM distributed_exec('CREATE ROLE dist_test_role');
|
||||
$$);
|
||||
\set ON_ERROR_STOP 1
|
||||
SELECT * FROM test.remote_exec(NULL, $$ SELECT true from pg_catalog.pg_roles WHERE rolname = 'dist_test_role'; $$);
|
||||
DROP ROLE DIST_TEST_ROLE;
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT test.execute_sql_and_filter_data_node_name_on_error($$
|
||||
SELECT * FROM distributed_exec('DROP ROLE dist_test_role');
|
||||
$$);
|
||||
\set ON_ERROR_STOP 1
|
||||
|
||||
-- Do not allow to run distributed_exec() on a data nodes
|
||||
\c data_node_1
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT * FROM distributed_exec('SELECT 1');
|
||||
\set ON_ERROR_STOP 1
|
||||
|
||||
\c :TEST_DBNAME :ROLE_SUPERUSER
|
||||
DROP DATABASE data_node1;
|
||||
DROP DATABASE data_node2;
|
||||
DROP DATABASE data_node3;
|
||||
DROP DATABASE data_node_1;
|
||||
DROP DATABASE data_node_2;
|
||||
DROP DATABASE data_node_3;
|
||||
|
Loading…
x
Reference in New Issue
Block a user