-- -- MULTI_EXTENSION -- -- Tests around extension creation / upgrades -- -- It'd be nice to script generation of this file, but alas, that's -- not done yet. -- differentiate the output file for pg11 and versions above, with regards to objects -- created per citus version depending on the postgres version. Upgrade tests verify the -- objects are added in citus_finish_pg_upgrade() SHOW server_version \gset SELECT substring(:'server_version', '\d+')::int > 11 AS version_above_eleven; version_above_eleven --------------------------------------------------------------------- f (1 row) SET citus.next_shard_id TO 580000; SELECT $definition$ CREATE OR REPLACE FUNCTION test.maintenance_worker() RETURNS pg_stat_activity LANGUAGE plpgsql AS $$ DECLARE activity record; BEGIN DO 'BEGIN END'; -- Force maintenance daemon to start -- we don't want to wait forever; loop will exit after 20 seconds FOR i IN 1 .. 200 LOOP PERFORM pg_stat_clear_snapshot(); SELECT * INTO activity FROM pg_stat_activity WHERE application_name = 'Citus Maintenance Daemon' AND datname = current_database(); IF activity.pid IS NOT NULL THEN RETURN activity; ELSE PERFORM pg_sleep(0.1); END IF ; END LOOP; -- fail if we reach the end of this loop raise 'Waited too long for maintenance daemon to start'; END; $$; $definition$ create_function_test_maintenance_worker \gset CREATE TABLE prev_objects(description text); CREATE TABLE extension_diff(previous_object text COLLATE "C", current_object text COLLATE "C"); CREATE FUNCTION print_extension_changes() RETURNS TABLE(previous_object text, current_object text) AS $func$ BEGIN TRUNCATE TABLE extension_diff; CREATE TABLE current_objects AS SELECT pg_catalog.pg_describe_object(classid, objid, 0) AS description FROM pg_catalog.pg_depend, pg_catalog.pg_extension e WHERE refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass AND refobjid = e.oid AND deptype = 'e' AND e.extname='citus'; INSERT INTO extension_diff SELECT p.description previous_object, c.description current_object FROM current_objects c FULL JOIN prev_objects p ON p.description = c.description WHERE p.description is null OR c.description is null; DROP TABLE prev_objects; ALTER TABLE current_objects RENAME TO prev_objects; RETURN QUERY SELECT * FROM extension_diff ORDER BY 1, 2; END $func$ LANGUAGE plpgsql; CREATE SCHEMA test; :create_function_test_maintenance_worker -- check maintenance daemon is started SELECT datname, current_database(), usename, (SELECT extowner::regrole::text FROM pg_extension WHERE extname = 'citus') FROM test.maintenance_worker(); datname | current_database | usename | extowner --------------------------------------------------------------------- regression | regression | postgres | postgres (1 row) -- ensure no unexpected objects were created outside pg_catalog SELECT pgio.type, pgio.identity FROM pg_depend AS pgd, pg_extension AS pge, LATERAL pg_identify_object(pgd.classid, pgd.objid, pgd.objsubid) AS pgio WHERE pgd.refclassid = 'pg_extension'::regclass AND pgd.refobjid = pge.oid AND pge.extname = 'citus' AND pgio.schema NOT IN ('pg_catalog', 'citus', 'citus_internal', 'test', 'columnar') ORDER BY 1, 2; type | identity --------------------------------------------------------------------- view | public.citus_tables (1 row) -- DROP EXTENSION pre-created by the regression suite DROP EXTENSION citus; \c -- these tests switch between citus versions and call ddl's that require pg_dist_object to be created SET citus.enable_object_propagation TO 'false'; SET citus.enable_version_checks TO 'false'; CREATE EXTENSION citus VERSION '8.0-1'; ALTER EXTENSION citus UPDATE TO '8.0-2'; ALTER EXTENSION citus UPDATE TO '8.0-3'; ALTER EXTENSION citus UPDATE TO '8.0-4'; ALTER EXTENSION citus UPDATE TO '8.0-5'; ALTER EXTENSION citus UPDATE TO '8.0-6'; ALTER EXTENSION citus UPDATE TO '8.0-7'; ALTER EXTENSION citus UPDATE TO '8.0-8'; ALTER EXTENSION citus UPDATE TO '8.0-9'; ALTER EXTENSION citus UPDATE TO '8.0-10'; ALTER EXTENSION citus UPDATE TO '8.0-11'; ALTER EXTENSION citus UPDATE TO '8.0-12'; ALTER EXTENSION citus UPDATE TO '8.0-13'; ALTER EXTENSION citus UPDATE TO '8.1-1'; ALTER EXTENSION citus UPDATE TO '8.2-1'; ALTER EXTENSION citus UPDATE TO '8.2-2'; ALTER EXTENSION citus UPDATE TO '8.2-3'; ALTER EXTENSION citus UPDATE TO '8.2-4'; ALTER EXTENSION citus UPDATE TO '8.3-1'; ALTER EXTENSION citus UPDATE TO '9.0-1'; ALTER EXTENSION citus UPDATE TO '9.0-2'; ALTER EXTENSION citus UPDATE TO '9.1-1'; ALTER EXTENSION citus UPDATE TO '9.2-1'; ALTER EXTENSION citus UPDATE TO '9.2-2'; -- Snapshot of state at 9.2-2 SELECT * FROM print_extension_changes(); previous_object | current_object --------------------------------------------------------------------- | event trigger citus_cascade_to_partition | function alter_role_if_exists(text,text) | function any_value(anyelement) | function any_value_agg(anyelement,anyelement) | function array_cat_agg(anyarray) | function assign_distributed_transaction_id(integer,bigint,timestamp with time zone) | function authinfo_valid(text) | function broadcast_intermediate_result(text,text) | function check_distributed_deadlocks() | function citus_add_rebalance_strategy(name,regproc,regproc,regproc,real,real) | function citus_blocking_pids(integer) | function citus_create_restore_point(text) | function citus_dist_stat_activity() | function citus_drop_trigger() | function citus_executor_name(integer) | function citus_extradata_container(internal) | function citus_finish_pg_upgrade() | function citus_internal.find_groupid_for_node(text,integer) | function citus_internal.pg_dist_node_trigger_func() | function citus_internal.pg_dist_rebalance_strategy_enterprise_check() | function citus_internal.pg_dist_rebalance_strategy_trigger_func() | function citus_internal.pg_dist_shard_placement_trigger_func() | function citus_internal.refresh_isolation_tester_prepared_statement() | function citus_internal.replace_isolation_tester_func() | function citus_internal.restore_isolation_tester_func() | function citus_isolation_test_session_is_blocked(integer,integer[]) | function citus_json_concatenate(json,json) | function citus_json_concatenate_final(json) | function citus_jsonb_concatenate(jsonb,jsonb) | function citus_jsonb_concatenate_final(jsonb) | function citus_node_capacity_1(integer) | function citus_prepare_pg_upgrade() | function citus_query_stats() | function citus_relation_size(regclass) | function citus_server_id() | function citus_set_default_rebalance_strategy(text) | function citus_shard_allowed_on_node_true(bigint,integer) | function citus_shard_cost_1(bigint) | function citus_shard_cost_by_disk_size(bigint) | function citus_stat_statements() | function citus_stat_statements_reset() | function citus_table_is_visible(oid) | function citus_table_size(regclass) | function citus_text_send_as_jsonb(text) | function citus_total_relation_size(regclass) | function citus_truncate_trigger() | function citus_validate_rebalance_strategy_functions(regproc,regproc,regproc) | function citus_version() | function citus_worker_stat_activity() | function column_name_to_column(regclass,text) | function column_to_column_name(regclass,text) | function coord_combine_agg(oid,cstring,anyelement) | function coord_combine_agg_ffunc(internal,oid,cstring,anyelement) | function coord_combine_agg_sfunc(internal,oid,cstring,anyelement) | function create_distributed_function(regprocedure,text,text) | function create_distributed_table(regclass,text,citus.distribution_type,text) | function create_intermediate_result(text,text) | function create_reference_table(regclass) | function distributed_tables_colocated(regclass,regclass) | function dump_global_wait_edges() | function dump_local_wait_edges() | function fetch_intermediate_results(text[],text,integer) | function get_all_active_transactions() | function get_colocated_shard_array(bigint) | function get_colocated_table_array(regclass) | function get_current_transaction_id() | function get_global_active_transactions() | function get_rebalance_progress() | function get_rebalance_table_shards_plan(regclass,real,integer,bigint[],boolean,name) | function get_shard_id_for_distribution_column(regclass,"any") | function isolate_tenant_to_new_shard(regclass,"any",text) | function json_cat_agg(json) | function jsonb_cat_agg(jsonb) | function lock_relation_if_exists(text,text) | function lock_shard_metadata(integer,bigint[]) | function lock_shard_resources(integer,bigint[]) | function mark_tables_colocated(regclass,regclass[]) | function master_activate_node(text,integer) | function master_add_inactive_node(text,integer,integer,noderole,name) | function master_add_node(text,integer,integer,noderole,name) | function master_add_secondary_node(text,integer,text,integer,name) | function master_append_table_to_shard(bigint,text,text,integer) | function master_apply_delete_command(text) | function master_conninfo_cache_invalidate() | function master_copy_shard_placement(bigint,text,integer,text,integer,boolean,citus.shard_transfer_mode) | function master_create_distributed_table(regclass,text,citus.distribution_type) | function master_create_empty_shard(text) | function master_create_worker_shards(text,integer,integer) | function master_disable_node(text,integer) | function master_dist_local_group_cache_invalidate() | function master_dist_node_cache_invalidate() | function master_dist_object_cache_invalidate() | function master_dist_partition_cache_invalidate() | function master_dist_placement_cache_invalidate() | function master_dist_shard_cache_invalidate() | function master_drain_node(text,integer,citus.shard_transfer_mode,name) | function master_drop_all_shards(regclass,text,text) | function master_drop_sequences(text[]) | function master_get_active_worker_nodes() | function master_get_new_placementid() | function master_get_new_shardid() | function master_get_table_ddl_events(text) | function master_get_table_metadata(text) | function master_modify_multiple_shards(text) | function master_move_shard_placement(bigint,text,integer,text,integer,citus.shard_transfer_mode) | function master_remove_distributed_table_metadata_from_workers(regclass,text,text) | function master_remove_node(text,integer) | function master_remove_partition_metadata(regclass,text,text) | function master_run_on_worker(text[],integer[],text[],boolean) | function master_set_node_property(text,integer,text,boolean) | function master_unmark_object_distributed(oid,oid,integer) | function master_update_node(integer,text,integer,boolean,integer) | function master_update_shard_statistics(bigint) | function master_update_table_statistics(regclass) | function poolinfo_valid(text) | function read_intermediate_result(text,citus_copy_format) | function read_intermediate_results(text[],citus_copy_format) | function rebalance_table_shards(regclass,real,integer,bigint[],citus.shard_transfer_mode,boolean,name) | function recover_prepared_transactions() | function relation_is_a_known_shard(regclass) | function replicate_table_shards(regclass,integer,integer,bigint[],citus.shard_transfer_mode) | function role_exists(name) | function run_command_on_colocated_placements(regclass,regclass,text,boolean) | function run_command_on_placements(regclass,text,boolean) | function run_command_on_shards(regclass,text,boolean) | function run_command_on_workers(text,boolean) | function shard_name(regclass,bigint) | function start_metadata_sync_to_node(text,integer) | function stop_metadata_sync_to_node(text,integer) | function task_tracker_assign_task(bigint,integer,text) | function task_tracker_cleanup_job(bigint) | function task_tracker_conninfo_cache_invalidate() | function task_tracker_task_status(bigint,integer) | function upgrade_to_reference_table(regclass) | function worker_append_table_to_shard(text,text,text,integer) | function worker_apply_inter_shard_ddl_command(bigint,text,bigint,text,text) | function worker_apply_sequence_command(text) | function worker_apply_sequence_command(text,regtype) | function worker_apply_shard_ddl_command(bigint,text) | function worker_apply_shard_ddl_command(bigint,text,text) | function worker_cleanup_job_schema_cache() | function worker_create_or_replace_object(text) | function worker_create_schema(bigint,text) | function worker_create_truncate_trigger(regclass) | function worker_drop_distributed_table(text) | function worker_execute_sql_task(bigint,integer,text,boolean) | function worker_fetch_foreign_file(text,text,bigint,text[],integer[]) | function worker_fetch_partition_file(bigint,integer,integer,integer,text,integer) | function worker_hash("any") | function worker_hash_partition_table(bigint,integer,text,text,oid,anyarray) | function worker_merge_files_and_run_query(bigint,integer,text,text) | function worker_merge_files_into_table(bigint,integer,text[],text[]) | function worker_partial_agg(oid,anyelement) | function worker_partial_agg_ffunc(internal) | function worker_partial_agg_sfunc(internal,oid,anyelement) | function worker_partition_query_result(text,text,integer,citus.distribution_type,text[],text[],boolean) | function worker_range_partition_table(bigint,integer,text,text,oid,anyarray) | function worker_repartition_cleanup(bigint) | schema citus | schema citus_internal | sequence pg_dist_colocationid_seq | sequence pg_dist_groupid_seq | sequence pg_dist_node_nodeid_seq | sequence pg_dist_placement_placementid_seq | sequence pg_dist_shardid_seq | table citus.pg_dist_object | table pg_dist_authinfo | table pg_dist_colocation | table pg_dist_local_group | table pg_dist_node | table pg_dist_node_metadata | table pg_dist_partition | table pg_dist_placement | table pg_dist_poolinfo | table pg_dist_rebalance_strategy | table pg_dist_shard | table pg_dist_transaction | type citus.distribution_type | type citus.shard_transfer_mode | type citus_copy_format | type noderole | view citus_dist_stat_activity | view citus_lock_waits | view citus_shard_indexes_on_worker | view citus_shards_on_worker | view citus_stat_statements | view citus_worker_stat_activity | view pg_dist_shard_placement (188 rows) -- Test downgrade to 9.2-2 from 9.2-4 ALTER EXTENSION citus UPDATE TO '9.2-4'; ALTER EXTENSION citus UPDATE TO '9.2-2'; -- Should be empty result since upgrade+downgrade should be a no-op SELECT * FROM print_extension_changes(); previous_object | current_object --------------------------------------------------------------------- (0 rows) /* * As we mistakenly bumped schema version to 9.3-1 in a bad release, we support * updating citus schema from 9.3-1 to 9.2-4, but we do not support updates to 9.3-1. * * Hence the query below should fail. */ ALTER EXTENSION citus UPDATE TO '9.3-1'; ERROR: extension "citus" has no update path from version "9.2-2" to version "9.3-1" ALTER EXTENSION citus UPDATE TO '9.2-4'; -- Snapshot of state at 9.2-4 SELECT * FROM print_extension_changes(); previous_object | current_object --------------------------------------------------------------------- (0 rows) -- Test downgrade to 9.2-4 from 9.3-2 ALTER EXTENSION citus UPDATE TO '9.3-2'; ALTER EXTENSION citus UPDATE TO '9.2-4'; -- Should be empty result since upgrade+downgrade should be a no-op SELECT * FROM print_extension_changes(); previous_object | current_object --------------------------------------------------------------------- (0 rows) -- Snapshot of state at 9.3-2 ALTER EXTENSION citus UPDATE TO '9.3-2'; SELECT * FROM print_extension_changes(); previous_object | current_object --------------------------------------------------------------------- | function citus_remote_connection_stats() | function replicate_reference_tables() | function truncate_local_data_after_distributing_table(regclass) | function update_distributed_table_colocation(regclass,text) | function worker_create_or_alter_role(text,text,text) (5 rows) -- Test downgrade to 9.3-2 from 9.4-1 ALTER EXTENSION citus UPDATE TO '9.4-1'; ALTER EXTENSION citus UPDATE TO '9.3-2'; -- Should be empty result since upgrade+downgrade should be a no-op SELECT * FROM print_extension_changes(); previous_object | current_object --------------------------------------------------------------------- (0 rows) -- Snapshot of state at 9.4-1 ALTER EXTENSION citus UPDATE TO '9.4-1'; SELECT * FROM print_extension_changes(); previous_object | current_object --------------------------------------------------------------------- | function worker_last_saved_explain_analyze() | function worker_save_query_explain_analyze(text,jsonb) (2 rows) -- Test downgrade to 9.4-1 from 9.5-1 ALTER EXTENSION citus UPDATE TO '9.5-1'; BEGIN; SELECT master_add_node('localhost', :master_port, groupId=>0); master_add_node --------------------------------------------------------------------- 1 (1 row) CREATE TABLE citus_local_table (a int); SELECT create_citus_local_table('citus_local_table'); create_citus_local_table --------------------------------------------------------------------- (1 row) -- downgrade from 9.5-1 to 9.4-1 should fail as we have a citus local table ALTER EXTENSION citus UPDATE TO '9.4-1'; ERROR: citus local tables are introduced in Citus 9.5 HINT: To downgrade Citus to an older version, you should first convert each citus local table to a postgres table by executing SELECT undistribute_table("%s") CONTEXT: PL/pgSQL function inline_code_block line 11 at RAISE ROLLBACK; -- now we can downgrade as there is no citus local table ALTER EXTENSION citus UPDATE TO '9.4-1'; -- Should be empty result since upgrade+downgrade should be a no-op SELECT * FROM print_extension_changes(); previous_object | current_object --------------------------------------------------------------------- (0 rows) -- Snapshot of state at 9.5-1 ALTER EXTENSION citus UPDATE TO '9.5-1'; SELECT * FROM print_extension_changes(); previous_object | current_object --------------------------------------------------------------------- function master_drop_sequences(text[]) | function task_tracker_assign_task(bigint,integer,text) | function task_tracker_cleanup_job(bigint) | function task_tracker_conninfo_cache_invalidate() | function task_tracker_task_status(bigint,integer) | function worker_execute_sql_task(bigint,integer,text,boolean) | function worker_merge_files_and_run_query(bigint,integer,text,text) | | function create_citus_local_table(regclass) | function undistribute_table(regclass) | function worker_record_sequence_dependency(regclass,regclass,name) (10 rows) -- Test downgrade to 9.5-1 from 10.0-1 ALTER EXTENSION citus UPDATE TO '10.0-1'; ALTER EXTENSION citus UPDATE TO '9.5-1'; -- Should be empty result since upgrade+downgrade should be a no-op SELECT * FROM print_extension_changes(); previous_object | current_object --------------------------------------------------------------------- (0 rows) -- Snapshot of state at 10.0-1 ALTER EXTENSION citus UPDATE TO '10.0-1'; SELECT * FROM print_extension_changes(); previous_object | current_object --------------------------------------------------------------------- function citus_total_relation_size(regclass) | function create_citus_local_table(regclass) | function undistribute_table(regclass) | function upgrade_to_reference_table(regclass) | | function citus_internal.columnar_ensure_objects_exist() | function citus_set_coordinator_host(text,integer,noderole,name) | function citus_total_relation_size(regclass,boolean) | function create_citus_local_table(regclass,boolean) | function time_partition_range(regclass) | function undistribute_table(regclass,boolean) | schema columnar | sequence columnar.storageid_seq | table columnar.columnar_skipnodes | table columnar.columnar_stripes | table columnar.options | view citus_tables | view time_partitions (17 rows) DROP TABLE prev_objects, extension_diff; -- show running version SHOW citus.version; citus.version --------------------------------------------------------------------- 10.0devel (1 row) -- ensure no unexpected objects were created outside pg_catalog SELECT pgio.type, pgio.identity FROM pg_depend AS pgd, pg_extension AS pge, LATERAL pg_identify_object(pgd.classid, pgd.objid, pgd.objsubid) AS pgio WHERE pgd.refclassid = 'pg_extension'::regclass AND pgd.refobjid = pge.oid AND pge.extname = 'citus' AND pgio.schema NOT IN ('pg_catalog', 'citus', 'citus_internal', 'test', 'columnar') ORDER BY 1, 2; type | identity --------------------------------------------------------------------- view | public.citus_tables (1 row) -- see incompatible version errors out RESET citus.enable_version_checks; DROP EXTENSION citus; CREATE EXTENSION citus VERSION '8.0-1'; ERROR: specified version incompatible with loaded Citus library DETAIL: Loaded library requires 10.0, but 8.0-1 was specified. HINT: If a newer library is present, restart the database and try the command again. -- Test non-distributed queries work even in version mismatch SET citus.enable_version_checks TO 'false'; CREATE EXTENSION citus VERSION '8.1-1'; SET citus.enable_version_checks TO 'true'; -- Test CREATE TABLE CREATE TABLE version_mismatch_table(column1 int); -- Test COPY \copy version_mismatch_table FROM STDIN; -- Test INSERT INSERT INTO version_mismatch_table(column1) VALUES(5); -- Test SELECT SELECT * FROM version_mismatch_table ORDER BY column1; column1 --------------------------------------------------------------------- 0 1 2 3 4 5 (6 rows) -- Test SELECT from pg_catalog SELECT d.datname as "Name", pg_catalog.pg_get_userbyid(d.datdba) as "Owner", pg_catalog.array_to_string(d.datacl, E'\n') AS "Access privileges" FROM pg_catalog.pg_database d ORDER BY 1; Name | Owner | Access privileges --------------------------------------------------------------------- postgres | postgres | regression | postgres | template0 | postgres | =c/postgres + | | postgres=CTc/postgres template1 | postgres | =c/postgres + | | postgres=CTc/postgres (4 rows) -- We should not distribute table in version mistmatch SELECT create_distributed_table('version_mismatch_table', 'column1'); ERROR: loaded Citus library version differs from installed extension version DETAIL: Loaded library requires 10.0, but the installed extension version is 8.1-1. HINT: Run ALTER EXTENSION citus UPDATE and try again. -- This function will cause fail in next ALTER EXTENSION CREATE OR REPLACE FUNCTION pg_catalog.relation_is_a_known_shard(regclass) RETURNS void LANGUAGE plpgsql AS $function$ BEGIN END; $function$; ERROR: cannot change return type of existing function HINT: Use DROP FUNCTION relation_is_a_known_shard(regclass) first. SET citus.enable_version_checks TO 'false'; -- This will fail because of previous function declaration ALTER EXTENSION citus UPDATE TO '8.1-1'; NOTICE: version "8.1-1" of extension "citus" is already installed -- We can DROP problematic function and continue ALTER EXTENSION even when version checks are on SET citus.enable_version_checks TO 'true'; DROP FUNCTION pg_catalog.relation_is_a_known_shard(regclass); ERROR: cannot drop function relation_is_a_known_shard(regclass) because extension citus requires it HINT: You can drop extension citus instead. SET citus.enable_version_checks TO 'false'; ALTER EXTENSION citus UPDATE TO '8.1-1'; NOTICE: version "8.1-1" of extension "citus" is already installed -- Test updating to the latest version without specifying the version number ALTER EXTENSION citus UPDATE; -- re-create in newest version DROP EXTENSION citus; \c CREATE EXTENSION citus; -- test cache invalidation in workers \c - - - :worker_1_port DROP EXTENSION citus; SET citus.enable_version_checks TO 'false'; CREATE EXTENSION citus VERSION '8.0-1'; SET citus.enable_version_checks TO 'true'; -- during ALTER EXTENSION, we should invalidate the cache ALTER EXTENSION citus UPDATE; -- if cache is invalidated succesfull, this \d should work without any problem \d List of relations Schema | Name | Type | Owner --------------------------------------------------------------------- public | citus_tables | view | postgres (1 row) \c - - - :master_port -- test https://github.com/citusdata/citus/issues/3409 CREATE USER testuser2 SUPERUSER; NOTICE: not propagating CREATE ROLE/USER commands to worker nodes HINT: Connect to worker nodes directly to manually create all necessary users and roles. SET ROLE testuser2; DROP EXTENSION Citus; -- Loop until we see there's no maintenance daemon running DO $$begin for i in 0 .. 100 loop if i = 100 then raise 'Waited too long'; end if; PERFORM pg_stat_clear_snapshot(); perform * from pg_stat_activity where application_name = 'Citus Maintenance Daemon'; if not found then exit; end if; perform pg_sleep(0.1); end loop; end$$; SELECT datid, datname, usename FROM pg_stat_activity WHERE application_name = 'Citus Maintenance Daemon'; datid | datname | usename --------------------------------------------------------------------- (0 rows) CREATE EXTENSION Citus; -- Loop until we there's a maintenance daemon running DO $$begin for i in 0 .. 100 loop if i = 100 then raise 'Waited too long'; end if; PERFORM pg_stat_clear_snapshot(); perform * from pg_stat_activity where application_name = 'Citus Maintenance Daemon'; if found then exit; end if; perform pg_sleep(0.1); end loop; end$$; SELECT datid, datname, usename FROM pg_stat_activity WHERE application_name = 'Citus Maintenance Daemon'; datid | datname | usename --------------------------------------------------------------------- 16384 | regression | testuser2 (1 row) RESET ROLE; -- check that maintenance daemon gets (re-)started for the right user DROP EXTENSION citus; CREATE USER testuser SUPERUSER; SET ROLE testuser; CREATE EXTENSION citus; SELECT datname, current_database(), usename, (SELECT extowner::regrole::text FROM pg_extension WHERE extname = 'citus') FROM test.maintenance_worker(); datname | current_database | usename | extowner --------------------------------------------------------------------- regression | regression | testuser | testuser (1 row) -- and recreate as the right owner RESET ROLE; DROP EXTENSION citus; CREATE EXTENSION citus; -- Check that maintenance daemon can also be started in another database CREATE DATABASE another; NOTICE: Citus partially supports CREATE DATABASE for distributed databases DETAIL: Citus does not propagate CREATE DATABASE command to workers HINT: You can manually create a database and its extensions on workers. \c another CREATE EXTENSION citus; CREATE SCHEMA test; :create_function_test_maintenance_worker -- see that the daemon started SELECT datname, current_database(), usename, (SELECT extowner::regrole::text FROM pg_extension WHERE extname = 'citus') FROM test.maintenance_worker(); datname | current_database | usename | extowner --------------------------------------------------------------------- another | another | postgres | postgres (1 row) -- Test that database with active worker can be dropped. \c regression CREATE SCHEMA test_daemon; -- we create a similar function on the regression database -- note that this function checks for the existence of the daemon -- when not found, returns true else tries for 5 times and -- returns false CREATE OR REPLACE FUNCTION test_daemon.maintenance_daemon_died(p_dbname text) RETURNS boolean LANGUAGE plpgsql AS $$ DECLARE activity record; BEGIN PERFORM pg_stat_clear_snapshot(); SELECT * INTO activity FROM pg_stat_activity WHERE application_name = 'Citus Maintenance Daemon' AND datname = p_dbname; IF activity.pid IS NULL THEN RETURN true; ELSE RETURN false; END IF; END; $$; -- drop the database and see that the daemon is dead DROP DATABASE another; SELECT * FROM test_daemon.maintenance_daemon_died('another'); maintenance_daemon_died --------------------------------------------------------------------- t (1 row) -- we don't need the schema and the function anymore DROP SCHEMA test_daemon CASCADE; NOTICE: drop cascades to function test_daemon.maintenance_daemon_died(text) -- verify citus does not crash while creating a table when run against an older worker -- create_distributed_table piggybacks multiple commands into single one, if one worker -- did not have the required UDF it should fail instead of crash. -- create a test database, configure citus with single node CREATE DATABASE another; NOTICE: Citus partially supports CREATE DATABASE for distributed databases DETAIL: Citus does not propagate CREATE DATABASE command to workers HINT: You can manually create a database and its extensions on workers. \c - - - :worker_1_port CREATE DATABASE another; NOTICE: Citus partially supports CREATE DATABASE for distributed databases DETAIL: Citus does not propagate CREATE DATABASE command to workers HINT: You can manually create a database and its extensions on workers. \c - - - :master_port \c another CREATE EXTENSION citus; SET citus.enable_object_propagation TO off; -- prevent distributed transactions during add node SELECT FROM master_add_node('localhost', :worker_1_port); WARNING: citus.enable_object_propagation is off, not creating distributed objects on worker DETAIL: distributed objects are only kept in sync when citus.enable_object_propagation is set to on. Newly activated nodes will not get these objects created -- (1 row) \c - - - :worker_1_port CREATE EXTENSION citus; ALTER FUNCTION assign_distributed_transaction_id(initiator_node_identifier integer, transaction_number bigint, transaction_stamp timestamp with time zone) RENAME TO dummy_assign_function; \c - - - :master_port SET citus.shard_replication_factor to 1; -- create_distributed_table command should fail CREATE TABLE t1(a int, b int); SET client_min_messages TO ERROR; DO $$ BEGIN BEGIN SELECT create_distributed_table('t1', 'a'); EXCEPTION WHEN OTHERS THEN RAISE 'create distributed table failed'; END; END; $$; ERROR: create distributed table failed CONTEXT: PL/pgSQL function inline_code_block line 6 at RAISE \c regression \c - - - :master_port DROP DATABASE another; \c - - - :worker_1_port DROP DATABASE another; \c - - - :master_port -- only the regression database should have a maintenance daemon SELECT count(*) FROM pg_stat_activity WHERE application_name = 'Citus Maintenance Daemon'; count --------------------------------------------------------------------- 1 (1 row) -- recreate the extension immediately after the maintenancae daemon errors SELECT pg_cancel_backend(pid) FROM pg_stat_activity WHERE application_name = 'Citus Maintenance Daemon'; pg_cancel_backend --------------------------------------------------------------------- t (1 row) DROP EXTENSION citus; CREATE EXTENSION citus; -- wait for maintenance daemon restart SELECT datname, current_database(), usename, (SELECT extowner::regrole::text FROM pg_extension WHERE extname = 'citus') FROM test.maintenance_worker(); datname | current_database | usename | extowner --------------------------------------------------------------------- regression | regression | postgres | postgres (1 row) -- confirm that there is only one maintenance daemon SELECT count(*) FROM pg_stat_activity WHERE application_name = 'Citus Maintenance Daemon'; count --------------------------------------------------------------------- 1 (1 row) -- kill the maintenance daemon SELECT pg_cancel_backend(pid) FROM pg_stat_activity WHERE application_name = 'Citus Maintenance Daemon'; pg_cancel_backend --------------------------------------------------------------------- t (1 row) -- reconnect \c - - - :master_port -- run something that goes through planner hook and therefore kicks of maintenance daemon SELECT 1; ?column? --------------------------------------------------------------------- 1 (1 row) -- wait for maintenance daemon restart SELECT datname, current_database(), usename, (SELECT extowner::regrole::text FROM pg_extension WHERE extname = 'citus') FROM test.maintenance_worker(); datname | current_database | usename | extowner --------------------------------------------------------------------- regression | regression | postgres | postgres (1 row) -- confirm that there is only one maintenance daemon SELECT count(*) FROM pg_stat_activity WHERE application_name = 'Citus Maintenance Daemon'; count --------------------------------------------------------------------- 1 (1 row) DROP TABLE version_mismatch_table;