diff --git a/extension/sql/common/cluster_setup_functions.sql b/extension/sql/common/cluster_setup_functions.sql index 1806ef38b..1f313c3dd 100644 --- a/extension/sql/common/cluster_setup_functions.sql +++ b/extension/sql/common/cluster_setup_functions.sql @@ -20,6 +20,7 @@ $BODY$; CREATE OR REPLACE FUNCTION _iobeamdb_internal.create_server( server_name NAME, hostname NAME, + port INT, database_name NAME ) RETURNS VOID LANGUAGE PLPGSQL VOLATILE AS @@ -27,7 +28,7 @@ $BODY$ BEGIN EXECUTE format( $$ - CREATE SERVER %I FOREIGN DATA WRAPPER postgres_fdw OPTIONS(host '%s', dbname '%s') ; - $$, server_name, hostname, database_name); + CREATE SERVER %I FOREIGN DATA WRAPPER postgres_fdw OPTIONS(host '%s', dbname '%s', port '%s'); + $$, server_name, hostname, database_name, port); END $BODY$; diff --git a/extension/sql/common/tables.sql b/extension/sql/common/tables.sql index 59b50b46d..c5011b362 100644 --- a/extension/sql/common/tables.sql +++ b/extension/sql/common/tables.sql @@ -10,6 +10,7 @@ CREATE TABLE IF NOT EXISTS _iobeamdb_catalog.node ( schema_name NAME NOT NULL UNIQUE, --the schema name with remote tables to _iobeamdb_catalog schema of the node server_name NAME NOT NULL UNIQUE, hostname TEXT NOT NULL, + port INT NOT NULL CONSTRAINT valid_port CHECK (port >= 0 AND port <= 65535), active BOOLEAN NOT NULL DEFAULT TRUE, id SERIAL NOT NULL UNIQUE -- id for node. used in naming ); @@ -20,6 +21,7 @@ SELECT pg_catalog.pg_extension_config_dump(pg_get_serial_sequence('_iobeamdb_cat CREATE TABLE IF NOT EXISTS _iobeamdb_catalog.meta ( database_name NAME NOT NULL PRIMARY KEY, hostname TEXT NOT NULL, + port INT NOT NULL, server_name NAME NOT NULL ); SELECT pg_catalog.pg_extension_config_dump('_iobeamdb_catalog.meta', ''); diff --git a/extension/sql/main/meta_info.sql b/extension/sql/main/meta_info.sql index d3d52c2e0..9c3900dbe 100644 --- a/extension/sql/main/meta_info.sql +++ b/extension/sql/main/meta_info.sql @@ -3,9 +3,10 @@ CREATE OR REPLACE FUNCTION _iobeamdb_internal.get_meta_server_name() $BODY$ DECLARE server_name TEXT; + port INT; BEGIN - SELECT m.server_name - INTO STRICT server_name + SELECT m.server_name, m.port + INTO STRICT server_name, port FROM _iobeamdb_catalog.meta m; RETURN server_name; diff --git a/extension/sql/main/meta_triggers.sql b/extension/sql/main/meta_triggers.sql index 9368113e7..f501a7b07 100644 --- a/extension/sql/main/meta_triggers.sql +++ b/extension/sql/main/meta_triggers.sql @@ -9,7 +9,7 @@ BEGIN END IF; IF NEW.database_name <> current_database() THEN - PERFORM _iobeamdb_internal.create_server(NEW.server_name, NEW.hostname, NEW.database_name); + PERFORM _iobeamdb_internal.create_server(NEW.server_name, NEW.hostname, NEW.port, NEW.database_name); FOR cluster_user_row IN SELECT * FROM _iobeamdb_catalog.cluster_user LOOP diff --git a/extension/sql/main/node_triggers.sql b/extension/sql/main/node_triggers.sql index 660922bc8..0c4a3dff5 100644 --- a/extension/sql/main/node_triggers.sql +++ b/extension/sql/main/node_triggers.sql @@ -9,7 +9,7 @@ BEGIN END IF; IF NEW.database_name <> current_database() THEN - PERFORM _iobeamdb_internal.create_server(NEW.server_name, NEW.hostname, NEW.database_name); + PERFORM _iobeamdb_internal.create_server(NEW.server_name, NEW.hostname, NEW.port, NEW.database_name); FOR cluster_user_row IN SELECT * FROM _iobeamdb_catalog.cluster_user LOOP diff --git a/extension/sql/meta/cluster.sql b/extension/sql/meta/cluster.sql index edc967701..fd6a4a8dd 100644 --- a/extension/sql/meta/cluster.sql +++ b/extension/sql/meta/cluster.sql @@ -2,7 +2,8 @@ -- Sets a database and hostname as a meta node. CREATE OR REPLACE FUNCTION set_meta( database_name NAME, - hostname TEXT + hostname TEXT, + port INT = 5432 ) RETURNS VOID LANGUAGE PLPGSQL VOLATILE AS $BODY$ @@ -15,8 +16,8 @@ BEGIN LIMIT 1; IF meta_row IS NULL THEN - INSERT INTO _iobeamdb_catalog.meta (database_name, hostname, server_name) - VALUES (database_name, hostname, database_name); + INSERT INTO _iobeamdb_catalog.meta (database_name, hostname, port, server_name) + VALUES (database_name, hostname, port, database_name); ELSE IF meta_row.database_name <> database_name OR meta_row.hostname <> hostname THEN RAISE EXCEPTION 'Changing meta info is not supported' @@ -29,21 +30,28 @@ $BODY$; -- Adds a new node to the cluster, with its database name and hostname. CREATE OR REPLACE FUNCTION add_node( database_name NAME, - hostname TEXT + hostname TEXT, + port INT = 5432 ) RETURNS VOID LANGUAGE PLPGSQL VOLATILE AS $BODY$ DECLARE schema_name NAME; + new_id REGCLASS; BEGIN - schema_name := format('remote_%s', database_name); + + BEGIN + + new_id := nextval(pg_get_serial_sequence('_iobeamdb_catalog.node', 'id')); + schema_name := format('remote_%s_%s', new_id, database_name); + IF database_name = current_database() THEN schema_name = '_iobeamdb_catalog'; END IF; - BEGIN - INSERT INTO _iobeamdb_catalog.node (database_name, schema_name, server_name, hostname) - VALUES (database_name, schema_name, database_name, hostname); + INSERT INTO _iobeamdb_catalog.node (database_name, schema_name, server_name, hostname, port, id) + VALUES (database_name, schema_name, database_name, hostname, port, new_id); + EXCEPTION WHEN SQLSTATE '42710' THEN RAISE EXCEPTION 'Node % already exists', database_name diff --git a/extension/sql/meta/node_triggers.sql b/extension/sql/meta/node_triggers.sql index 1aba48903..d31a3f690 100644 --- a/extension/sql/meta/node_triggers.sql +++ b/extension/sql/meta/node_triggers.sql @@ -13,7 +13,7 @@ BEGIN NEW.schema_name); IF NEW.database_name <> current_database() THEN - PERFORM _iobeamdb_internal.create_server(NEW.server_name, NEW.hostname, NEW.database_name); + PERFORM _iobeamdb_internal.create_server(NEW.server_name, NEW.hostname, NEW.port, NEW.database_name); PERFORM _iobeamdb_internal.create_user_mapping(cluster_user, NEW.server_name) FROM _iobeamdb_catalog.cluster_user; diff --git a/extension/sql/tests/regression/cluster.sql b/extension/sql/tests/regression/cluster.sql index ff615f678..708ee609c 100644 --- a/extension/sql/tests/regression/cluster.sql +++ b/extension/sql/tests/regression/cluster.sql @@ -13,6 +13,13 @@ SELECT add_node('Test1' :: NAME, 'localhost'); SELECT add_node('test2' :: NAME, 'localhost'); + +\set ON_ERROR_STOP 0 +SELECT add_node('should_fail' :: NAME, 'localhost', -1); +SELECT add_node('should_fail' :: NAME, '!@#€%&%&(%#&())', 5432); + +\set ON_ERROR_STOP 1 + \c Test1 CREATE TABLE PUBLIC."testNs" ( @@ -135,6 +142,7 @@ FROM _iobeamdb_meta.get_or_create_chunk(1, 1257894000000000000 :: BIGINT); SELECT * FROM _iobeamdb_catalog.chunk; + \c Test1 \d+ "_iobeamdb_internal".* diff --git a/extension/sql/tests/regression/expected/cluster.out b/extension/sql/tests/regression/expected/cluster.out index 6027a5983..a2a69a6ad 100644 --- a/extension/sql/tests/regression/expected/cluster.out +++ b/extension/sql/tests/regression/expected/cluster.out @@ -56,6 +56,16 @@ SELECT add_node('test2' :: NAME, 'localhost'); (1 row) +\set ON_ERROR_STOP 0 +SELECT add_node('should_fail' :: NAME, 'localhost', -1); +psql:cluster.sql:18: ERROR: 08001: could not connect to server "should_fail" +DETAIL: invalid port number: "-1" +LOCATION: connect_pg_server, connection.c:241 +SELECT add_node('should_fail' :: NAME, '!@#€%&%&(%#&())', 5432); +psql:cluster.sql:19: ERROR: 08001: could not connect to server "should_fail" +DETAIL: could not translate host name "!@#€%&%&(%#&())" to address: Name or service not known +LOCATION: connect_pg_server, connection.c:241 +\set ON_ERROR_STOP 1 \c Test1 CREATE TABLE PUBLIC."testNs" ( time BIGINT NOT NULL, @@ -65,7 +75,7 @@ CREATE TABLE PUBLIC."testNs" ( latitude BIGINT NULL, really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_and_on_and_on BIGINT NULL ); -psql:cluster.sql:25: NOTICE: 42622: identifier "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_and_on_and_on" will be truncated to "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_a" +psql:cluster.sql:32: NOTICE: 42622: identifier "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_and_on_and_on" will be truncated to "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_a" LOCATION: truncate_identifier, scansup.c:205 CREATE TABLE PUBLIC."testNs2" ( time BIGINT NOT NULL, @@ -75,19 +85,19 @@ CREATE TABLE PUBLIC."testNs2" ( latitude BIGINT NULL, really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_and_on_and_on BIGINT NULL ); -psql:cluster.sql:34: NOTICE: 42622: identifier "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_and_on_and_on" will be truncated to "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_a" +psql:cluster.sql:41: NOTICE: 42622: identifier "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_and_on_and_on" will be truncated to "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_a" LOCATION: truncate_identifier, scansup.c:205 CREATE INDEX ON PUBLIC."testNs" ("Device_id", time DESC NULLS LAST) WHERE "Device_id" IS NOT NULL; CREATE INDEX ON PUBLIC."testNs" (temp, time DESC NULLS LAST) WHERE temp IS NOT NULL; CREATE INDEX ON PUBLIC."testNs" (really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_and_on_and_on, time DESC NULLS LAST) WHERE really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_and_on_and_on IS NOT NULL; -psql:cluster.sql:38: NOTICE: 42622: identifier "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_and_on_and_on" will be truncated to "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_a" +psql:cluster.sql:45: NOTICE: 42622: identifier "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_and_on_and_on" will be truncated to "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_a" LOCATION: truncate_identifier, scansup.c:205 -psql:cluster.sql:38: NOTICE: 42622: identifier "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_and_on_and_on" will be truncated to "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_a" +psql:cluster.sql:45: NOTICE: 42622: identifier "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_and_on_and_on" will be truncated to "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_a" LOCATION: truncate_identifier, scansup.c:205 CREATE INDEX ON PUBLIC."testNs" (time DESC NULLS LAST, really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_and_on_and_on) WHERE really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_and_on_and_on IS NOT NULL; -psql:cluster.sql:39: NOTICE: 42622: identifier "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_and_on_and_on" will be truncated to "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_a" +psql:cluster.sql:46: NOTICE: 42622: identifier "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_and_on_and_on" will be truncated to "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_a" LOCATION: truncate_identifier, scansup.c:205 -psql:cluster.sql:39: NOTICE: 42622: identifier "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_and_on_and_on" will be truncated to "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_a" +psql:cluster.sql:46: NOTICE: 42622: identifier "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_and_on_and_on" will be truncated to "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_a" LOCATION: truncate_identifier, scansup.c:205 SELECT * FROM create_hypertable('"public"."testNs"', 'time', 'Device_id'); create_hypertable @@ -97,7 +107,7 @@ SELECT * FROM create_hypertable('"public"."testNs"', 'time', 'Device_id'); \set ON_ERROR_STOP 0 SELECT * FROM create_hypertable('"public"."testNs"', 'time', 'Device_id'); -psql:cluster.sql:45: ERROR: IO110: hypertable public."testNs" already exists +psql:cluster.sql:52: ERROR: IO110: hypertable public."testNs" already exists LOCATION: exec_stmt_raise, pl_exec.c:3165 \set ON_ERROR_STOP 1 SELECT * FROM create_hypertable('"public"."testNs2"', 'time', 'Device_id'); @@ -126,17 +136,17 @@ FROM _iobeamdb_meta.get_or_create_chunk(1, 1257894000000000000 :: BIGINT); SELECT * FROM _iobeamdb_catalog.node; - database_name | schema_name | server_name | hostname | active | id ----------------+--------------+-------------+-----------+--------+---- - Test1 | remote_Test1 | Test1 | localhost | t | 1 - test2 | remote_test2 | test2 | localhost | t | 2 + database_name | schema_name | server_name | hostname | port | active | id +---------------+----------------+-------------+-----------+------+--------+---- + Test1 | remote_1_Test1 | Test1 | localhost | 5432 | t | 1 + test2 | remote_2_test2 | test2 | localhost | 5432 | t | 2 (2 rows) SELECT * FROM _iobeamdb_catalog.meta; - database_name | hostname | server_name ----------------+-----------+------------- - meta | localhost | meta + database_name | hostname | port | server_name +---------------+-----------+------+------------- + meta | localhost | 5432 | meta (1 row) SELECT * @@ -216,11 +226,11 @@ FROM _iobeamdb_catalog.hypertable_column; (12 rows) \des+ - List of foreign servers - Name | Owner | Foreign-data wrapper | Access privileges | Type | Version | FDW Options | Description --------+----------+----------------------+-------------------+------+---------+------------------------------------+------------- - Test1 | postgres | postgres_fdw | | | | (host 'localhost', dbname 'Test1') | - test2 | postgres | postgres_fdw | | | | (host 'localhost', dbname 'test2') | + List of foreign servers + Name | Owner | Foreign-data wrapper | Access privileges | Type | Version | FDW Options | Description +-------+----------+----------------------+-------------------+------+---------+-------------------------------------------------+------------- + Test1 | postgres | postgres_fdw | | | | (host 'localhost', dbname 'Test1', port '5432') | + test2 | postgres | postgres_fdw | | | | (host 'localhost', dbname 'test2', port '5432') | (2 rows) \deu+ @@ -236,17 +246,17 @@ FROM _iobeamdb_catalog.hypertable_column; \c Test1 SELECT * FROM _iobeamdb_catalog.node; - database_name | schema_name | server_name | hostname | active | id ----------------+--------------+-------------+-----------+--------+---- - Test1 | remote_Test1 | Test1 | localhost | t | 1 - test2 | remote_test2 | test2 | localhost | t | 2 + database_name | schema_name | server_name | hostname | port | active | id +---------------+----------------+-------------+-----------+------+--------+---- + Test1 | remote_1_Test1 | Test1 | localhost | 5432 | t | 1 + test2 | remote_2_test2 | test2 | localhost | 5432 | t | 2 (2 rows) SELECT * FROM _iobeamdb_catalog.meta; - database_name | hostname | server_name ----------------+-----------+------------- - meta | localhost | meta + database_name | hostname | port | server_name +---------------+-----------+------+------------- + meta | localhost | 5432 | meta (1 row) SELECT * @@ -327,24 +337,24 @@ FROM _iobeamdb_catalog.hypertable_column; \set ON_ERROR_STOP 0 UPDATE _iobeamdb_catalog.cluster_user SET password = 'foo'; -psql:cluster.sql:105: ERROR: IO101: Operation UPDATE not supported on _iobeamdb_catalog.cluster_user +psql:cluster.sql:112: ERROR: IO101: Operation UPDATE not supported on _iobeamdb_catalog.cluster_user LOCATION: exec_stmt_raise, pl_exec.c:3165 UPDATE _iobeamdb_catalog.node SET active = FALSE; -psql:cluster.sql:106: ERROR: IO101: Operation UPDATE not supported on _iobeamdb_catalog.node +psql:cluster.sql:113: ERROR: IO101: Operation UPDATE not supported on _iobeamdb_catalog.node LOCATION: exec_stmt_raise, pl_exec.c:3165 DELETE FROM _iobeamdb_catalog.meta WHERE TRUE; -psql:cluster.sql:107: ERROR: IO101: Operation DELETE not supported on _iobeamdb_catalog.meta +psql:cluster.sql:114: ERROR: IO101: Operation DELETE not supported on _iobeamdb_catalog.meta LOCATION: exec_stmt_raise, pl_exec.c:3165 TRUNCATE TABLE _iobeamdb_catalog.meta; -psql:cluster.sql:108: ERROR: IO101: Operation TRUNCATE not supported on _iobeamdb_catalog.meta +psql:cluster.sql:115: ERROR: IO101: Operation TRUNCATE not supported on _iobeamdb_catalog.meta LOCATION: exec_stmt_raise, pl_exec.c:3165 \set ON_ERROR_STOP 1 \des+ - List of foreign servers - Name | Owner | Foreign-data wrapper | Access privileges | Type | Version | FDW Options | Description --------+----------+----------------------+-------------------+------+---------+------------------------------------+------------- - meta | postgres | postgres_fdw | | | | (host 'localhost', dbname 'meta') | - test2 | postgres | postgres_fdw | | | | (host 'localhost', dbname 'test2') | + List of foreign servers + Name | Owner | Foreign-data wrapper | Access privileges | Type | Version | FDW Options | Description +-------+----------+----------------------+-------------------+------+---------+-------------------------------------------------+------------- + meta | postgres | postgres_fdw | | | | (host 'localhost', dbname 'meta', port '5432') | + test2 | postgres | postgres_fdw | | | | (host 'localhost', dbname 'test2', port '5432') | (2 rows) \deu+ @@ -604,7 +614,7 @@ Child tables: _iobeamdb_internal._hyper_3_0_replica \c meta SELECT _iobeamdb_meta.close_chunk_end(1); -psql:cluster.sql:127: WARNING: 01000: Cannot close an empty chunk table +psql:cluster.sql:134: WARNING: 01000: Cannot close an empty chunk table LOCATION: exec_stmt_raise, pl_exec.c:3165 close_chunk_end ----------------- @@ -767,11 +777,11 @@ CREATE TABLE PUBLIC."testNsOnMeta" ( latitude BIGINT NULL, really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_and_on_and_on BIGINT NULL ); -psql:cluster.sql:150: NOTICE: 42622: identifier "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_and_on_and_on" will be truncated to "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_a" +psql:cluster.sql:158: NOTICE: 42622: identifier "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_and_on_and_on" will be truncated to "really_long_column_goes_on_and_on_and_on_and_on_and_on_and_on_a" LOCATION: truncate_identifier, scansup.c:205 \set ON_ERROR_STOP 0 SELECT * FROM create_hypertable('"public"."testNsOnMeta"', 'time', 'Device_id'); -psql:cluster.sql:153: ERROR: IO101: database not configured for hypertable storage (not setup as a data-node) +psql:cluster.sql:161: ERROR: IO101: database not configured for hypertable storage (not setup as a data-node) LOCATION: exec_stmt_raise, pl_exec.c:3165 \set ON_ERROR_STOP 1 DROP TABLE PUBLIC."testNsOnMeta";