From d4c33b3cea712ddafeb3d1a6b08b28592b056b9d Mon Sep 17 00:00:00 2001 From: Onur Tirtir Date: Mon, 17 Feb 2020 20:52:17 +0300 Subject: [PATCH] add new tests --- .../local_shard_utility_command_execution.out | 555 ++++++++++++++++++ src/test/regress/multi_schedule | 3 +- .../local_shard_utility_command_execution.sql | 298 ++++++++++ 3 files changed, 855 insertions(+), 1 deletion(-) create mode 100644 src/test/regress/expected/local_shard_utility_command_execution.out create mode 100644 src/test/regress/sql/local_shard_utility_command_execution.sql diff --git a/src/test/regress/expected/local_shard_utility_command_execution.out b/src/test/regress/expected/local_shard_utility_command_execution.out new file mode 100644 index 000000000..e8c2b370a --- /dev/null +++ b/src/test/regress/expected/local_shard_utility_command_execution.out @@ -0,0 +1,555 @@ +-- This tests file includes tests for local execution of utility commands. +-- For now, this file includes tests only for local execution of +-- `TRUNCATE/DROP/DDL` commands for all kinds of distributed tables from +-- the coordinator node having regular distributed tables' shards +-- (shouldHaveShards = on) and having reference table placements in it. +\set VERBOSITY terse +SET citus.next_shard_id TO 1500000; +SET citus.shard_replication_factor TO 1; +SET citus.enable_local_execution TO ON; +SET citus.shard_COUNT TO 32; +SET citus.log_local_commands TO ON; +CREATE SCHEMA local_commands_test_schema; +SET search_path TO local_commands_test_schema; +-- let coordinator have distributed table shards/placements +SELECT master_add_node('localhost', :master_port, groupId => 0); + master_add_node +--------------------------------------------------------------------- + 1380010 +(1 row) + +SELECT master_set_node_property('localhost', :master_port, 'shouldhaveshards', true); + master_set_node_property +--------------------------------------------------------------------- + +(1 row) + +--------------------------------------------------------------------- +------ local execution of TRUNCATE ------ +--------------------------------------------------------------------- +CREATE TABLE ref_table (a int primary key); +SELECT create_reference_table('ref_table'); + create_reference_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE dist_table(a int); +SELECT create_distributed_table('dist_table', 'a'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +ALTER TABLE dist_table ADD CONSTRAINT fkey FOREIGN KEY(a) REFERENCES ref_table(a); +-- insert some data +INSERT INTO ref_table VALUES(1); +NOTICE: executing the command locally: INSERT INTO local_commands_test_schema.ref_table_1500000 (a) VALUES (1) +INSERT INTO dist_table VALUES(1); +-- Currently, we support local execution of TRUNCATE commands for all kinds +-- Hence, cascading to distributed tables wouldn't be a problem even in the +-- case that coordinator have some local distributed table shards. +TRUNCATE ref_table CASCADE; +NOTICE: truncate cascades to table "dist_table" +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.ref_table_1500000 CASCADE +NOTICE: truncate cascades to table "dist_table_1500001" +NOTICE: truncate cascades to table "dist_table_1500004" +NOTICE: truncate cascades to table "dist_table_1500007" +NOTICE: truncate cascades to table "dist_table_1500010" +NOTICE: truncate cascades to table "dist_table_1500013" +NOTICE: truncate cascades to table "dist_table_1500016" +NOTICE: truncate cascades to table "dist_table_1500019" +NOTICE: truncate cascades to table "dist_table_1500022" +NOTICE: truncate cascades to table "dist_table_1500025" +NOTICE: truncate cascades to table "dist_table_1500028" +NOTICE: truncate cascades to table "dist_table_1500031" +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500001 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500004 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500007 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500010 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500013 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500016 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500019 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500022 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500025 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500028 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500031 CASCADE +-- show that TRUNCATE is successfull +SELECT COUNT(*) FROM ref_table, dist_table; + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- insert some data +INSERT INTO ref_table VALUES(1); +NOTICE: executing the command locally: INSERT INTO local_commands_test_schema.ref_table_1500000 (a) VALUES (1) +INSERT INTO dist_table VALUES(1); +-- As SELECT accesses local placements of reference table, TRUNCATE would also +-- be forced to local execution even if they operate on different tables. +BEGIN; + SELECT COUNT(*) FROM ref_table; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_commands_test_schema.ref_table_1500000 ref_table + count +--------------------------------------------------------------------- + 1 +(1 row) + + TRUNCATE dist_table; +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500001 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500004 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500007 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500010 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500013 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500016 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500019 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500022 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500025 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500028 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500031 CASCADE +COMMIT; +-- show that TRUNCATE is successfull +SELECT COUNT(*) FROM dist_table; + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- insert some data +INSERT INTO ref_table VALUES(2); +NOTICE: executing the command locally: INSERT INTO local_commands_test_schema.ref_table_1500000 (a) VALUES (2) +INSERT INTO dist_table VALUES(2); +NOTICE: executing the command locally: INSERT INTO local_commands_test_schema.dist_table_1500025 (a) VALUES (2) +-- However, SELECT would access local placements via remote connections +-- for regular distributed tables, TRUNCATE would also be executed remotely. +BEGIN; + SELECT COUNT(*) FROM dist_table; + count +--------------------------------------------------------------------- + 1 +(1 row) + + TRUNCATE dist_table; +COMMIT; +-- show that TRUNCATE is successfull +SELECT COUNT(*) FROM dist_table; + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- insert some data +INSERT INTO ref_table VALUES(3); +NOTICE: executing the command locally: INSERT INTO local_commands_test_schema.ref_table_1500000 (a) VALUES (3) +INSERT INTO dist_table VALUES(3); +NOTICE: executing the command locally: INSERT INTO local_commands_test_schema.dist_table_1500016 (a) VALUES (3) +-- TRUNCATE on dist_table (note that: again no cascade here) would +-- just be handled via remote executions even on its local shards +TRUNCATE dist_table; +-- show that TRUNCATE is successfull +SELECT COUNT(*) FROM dist_table; + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- insert some data +INSERT INTO ref_table VALUES(4); +NOTICE: executing the command locally: INSERT INTO local_commands_test_schema.ref_table_1500000 (a) VALUES (4) +-- However, creating a dist. table is handled by remote connections. +-- Hence, the commands following it (INSERT & TRUNCATE) would also be +-- handled remotely. +BEGIN; + CREATE TABLE ref_table_1(a int); + SELECT create_reference_table('ref_table_1'); + create_reference_table +--------------------------------------------------------------------- + +(1 row) + + -- insert some data + INSERT INTO ref_table_1 VALUES(5); + TRUNCATE ref_table_1; +COMMIT; +-- show that TRUNCATE is successfull +SELECT COUNT(*) FROM ref_table_1; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_commands_test_schema.ref_table_1_1500033 ref_table_1 + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- However, as SELECT would access local placements via remote parallel +-- connections for regular distributed tables, below TRUNCATE would error +-- out +BEGIN; + SELECT COUNT(*) FROM dist_table; + count +--------------------------------------------------------------------- + 0 +(1 row) + + TRUNCATE ref_table CASCADE; +NOTICE: truncate cascades to table "dist_table" +ERROR: cannot execute DDL on reference table "ref_table" because there was a parallel SELECT access to distributed table "dist_table" in the same transaction +COMMIT; +-- insert some data +INSERT INTO ref_table VALUES(7); +NOTICE: executing the command locally: INSERT INTO local_commands_test_schema.ref_table_1500000 (a) VALUES (7) +INSERT INTO dist_table VALUES(7); +-- we can TRUNCATE those two tables within the same command +TRUNCATE ref_table, dist_table; +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.ref_table_1500000 CASCADE +NOTICE: truncate cascades to table "dist_table_1500001" +NOTICE: truncate cascades to table "dist_table_1500004" +NOTICE: truncate cascades to table "dist_table_1500007" +NOTICE: truncate cascades to table "dist_table_1500010" +NOTICE: truncate cascades to table "dist_table_1500013" +NOTICE: truncate cascades to table "dist_table_1500016" +NOTICE: truncate cascades to table "dist_table_1500019" +NOTICE: truncate cascades to table "dist_table_1500022" +NOTICE: truncate cascades to table "dist_table_1500025" +NOTICE: truncate cascades to table "dist_table_1500028" +NOTICE: truncate cascades to table "dist_table_1500031" +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500001 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500004 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500007 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500010 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500013 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500016 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500019 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500022 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500025 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500028 CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_commands_test_schema.dist_table_1500031 CASCADE +-- show that TRUNCATE is successfull +SELECT COUNT(*) FROM ref_table, dist_table; + count +--------------------------------------------------------------------- + 0 +(1 row) + +--------------------------------------------------------------------- +------ local execution of DROP ------ +--------------------------------------------------------------------- +-- droping just the referenced table would error out as dist_table references it +DROP TABLE ref_table; +ERROR: cannot drop table ref_table because other objects depend on it +-- drop those two tables via remote execution +DROP TABLE ref_table, dist_table; +-- drop the other standalone table locally +DROP TABLE ref_table_1; +NOTICE: executing the command locally: DROP TABLE IF EXISTS local_commands_test_schema.ref_table_1_1500033 CASCADE +-- show that DROP commands are successfull +SELECT tablename FROM pg_tables where schemaname='local_commands_test_schema' ORDER BY tablename; + tablename +--------------------------------------------------------------------- +(0 rows) + +CREATE TABLE ref_table (a int primary key); +SELECT create_reference_table('ref_table'); + create_reference_table +--------------------------------------------------------------------- + +(1 row) + +-- We execute SELECT command within the below block locally. +-- Hence we should execute the DROP command locally as well. +BEGIN; + SELECT COUNT(*) FROM ref_table; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_commands_test_schema.ref_table_1500034 ref_table + count +--------------------------------------------------------------------- + 0 +(1 row) + + DROP TABLE ref_table; +NOTICE: executing the command locally: DROP TABLE IF EXISTS local_commands_test_schema.ref_table_1500034 CASCADE +COMMIT; +CREATE TABLE ref_table (a int primary key); +SELECT create_reference_table('ref_table'); + create_reference_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE dist_table(a int); +SELECT create_distributed_table('dist_table', 'a'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +ALTER TABLE dist_table ADD CONSTRAINT fkey FOREIGN KEY(a) REFERENCES ref_table(a); +-- As both commands will prefer remote exeuction, TRUNCATE would be aware of +-- dist_table is dropped. Hence, below block should not be effective as TRUNCATE +-- will error out. +BEGIN; + DROP TABLE dist_table CASCADE; + TRUNCATE dist_table; +ERROR: relation "dist_table" does not exist +COMMIT; +-- show that DROP command is rollback'd successfully (should print 1) +SELECT 1 FROM pg_tables where tablename='dist_table'; + ?column? +--------------------------------------------------------------------- + 1 +(1 row) + +-- As SELECT will be executed remotely, the DROP command should also be executed +-- remotely to prevent possible self-deadlocks & inconsistencies. +-- FIXME: we have a known bug for below case described in +-- https://github.com/citusdata/citus/issues/3526. Hence, commented out as it could +-- randomly fall into distributed deadlocks +--BEGIN; +-- SELECT COUNT(*) FROM dist_table; +-- DROP TABLE dist_table; +--END; +-- As SELECT will be executed remotely, the DROP command below should also be +-- executed remotely. +CREATE TABLE another_dist_table(a int); +SELECT create_distributed_table('another_dist_table', 'a'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +BEGIN; + SELECT COUNT(*) FROM another_dist_table; + count +--------------------------------------------------------------------- + 0 +(1 row) + + DROP TABLE another_dist_table; +COMMIT; +-- show that DROP command is committed successfully +SELECT 1 FROM pg_tables where tablename='another_dist_table'; + ?column? +--------------------------------------------------------------------- +(0 rows) + +-- below DROP will be executed remotely. +DROP TABLE dist_table; +-- show that DROP command is successfull +SELECT 1 FROM pg_tables where tablename='dist_table'; + ?column? +--------------------------------------------------------------------- +(0 rows) + +CREATE TABLE dist_table(a int); +SELECT create_distributed_table('dist_table', 'a'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +ALTER TABLE dist_table ADD CONSTRAINT fkey FOREIGN KEY(a) REFERENCES ref_table(a); +-- as SELECT on ref_table will be executed locally, the SELECT and DROP following +-- it would also be executed locally +BEGIN; + SELECT COUNT(*) FROM ref_table; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_commands_test_schema.ref_table_1500035 ref_table + count +--------------------------------------------------------------------- + 0 +(1 row) + + DROP TABLE dist_table CASCADE; +NOTICE: executing the command locally: DROP TABLE IF EXISTS local_commands_test_schema.dist_table_1500100 CASCADE +NOTICE: executing the command locally: DROP TABLE IF EXISTS local_commands_test_schema.dist_table_1500103 CASCADE +NOTICE: executing the command locally: DROP TABLE IF EXISTS local_commands_test_schema.dist_table_1500106 CASCADE +NOTICE: executing the command locally: DROP TABLE IF EXISTS local_commands_test_schema.dist_table_1500109 CASCADE +NOTICE: executing the command locally: DROP TABLE IF EXISTS local_commands_test_schema.dist_table_1500112 CASCADE +NOTICE: executing the command locally: DROP TABLE IF EXISTS local_commands_test_schema.dist_table_1500115 CASCADE +NOTICE: executing the command locally: DROP TABLE IF EXISTS local_commands_test_schema.dist_table_1500118 CASCADE +NOTICE: executing the command locally: DROP TABLE IF EXISTS local_commands_test_schema.dist_table_1500121 CASCADE +NOTICE: executing the command locally: DROP TABLE IF EXISTS local_commands_test_schema.dist_table_1500124 CASCADE +NOTICE: executing the command locally: DROP TABLE IF EXISTS local_commands_test_schema.dist_table_1500127 CASCADE +NOTICE: executing the command locally: DROP TABLE IF EXISTS local_commands_test_schema.dist_table_1500130 CASCADE +ROLLBACK; +-- show that DROP command is rollback'd successfully (should print 1) +SELECT 1 FROM pg_tables where tablename='dist_table'; + ?column? +--------------------------------------------------------------------- + 1 +(1 row) + +--------------------------------------------------------------------- +------ local execution of DDL commands ------ +--------------------------------------------------------------------- +-- try some complicated CASCADE cases along with DDL commands +CREATE TABLE ref_table_1(a int primary key); +SELECT create_reference_table('ref_table_1'); + create_reference_table +--------------------------------------------------------------------- + +(1 row) + +-- below block should execute successfully +BEGIN; + SELECT COUNT(*) FROM ref_table; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_commands_test_schema.ref_table_1500035 ref_table + count +--------------------------------------------------------------------- + 0 +(1 row) + + -- as SELECT above runs locally and as now we support local execution of DDL commands, + -- below DDL should be able to define foreign key constraint successfully + ALTER TABLE ref_table ADD CONSTRAINT fkey FOREIGN KEY(a) REFERENCES ref_table_1(a); +NOTICE: executing the command locally: SELECT worker_apply_inter_shard_ddl_command (1500035, 'local_commands_test_schema', 1500132, 'local_commands_test_schema', 'ALTER TABLE ref_table ADD CONSTRAINT fkey FOREIGN KEY(a) REFERENCES ref_table_1(a);') + -- insert some data + INSERT INTO ref_table_1 VALUES (1); +NOTICE: executing the command locally: INSERT INTO local_commands_test_schema.ref_table_1_1500132 (a) VALUES (1) + INSERT INTO ref_table_1 VALUES (2); +NOTICE: executing the command locally: INSERT INTO local_commands_test_schema.ref_table_1_1500132 (a) VALUES (2) + INSERT INTO ref_table VALUES (1); +NOTICE: executing the command locally: INSERT INTO local_commands_test_schema.ref_table_1500035 (a) VALUES (1) + -- chain foreign key constraints + -- local execution should be observed here as well + ALTER TABLE dist_table ADD CONSTRAINT fkey1 FOREIGN KEY(a) REFERENCES ref_table(a); +NOTICE: executing the command locally: SELECT worker_apply_inter_shard_ddl_command (1500100, 'local_commands_test_schema', 1500035, 'local_commands_test_schema', 'ALTER TABLE dist_table ADD CONSTRAINT fkey1 FOREIGN KEY(a) REFERENCES ref_table(a);') +NOTICE: executing the command locally: SELECT worker_apply_inter_shard_ddl_command (1500103, 'local_commands_test_schema', 1500035, 'local_commands_test_schema', 'ALTER TABLE dist_table ADD CONSTRAINT fkey1 FOREIGN KEY(a) REFERENCES ref_table(a);') +NOTICE: executing the command locally: SELECT worker_apply_inter_shard_ddl_command (1500106, 'local_commands_test_schema', 1500035, 'local_commands_test_schema', 'ALTER TABLE dist_table ADD CONSTRAINT fkey1 FOREIGN KEY(a) REFERENCES ref_table(a);') +NOTICE: executing the command locally: SELECT worker_apply_inter_shard_ddl_command (1500109, 'local_commands_test_schema', 1500035, 'local_commands_test_schema', 'ALTER TABLE dist_table ADD CONSTRAINT fkey1 FOREIGN KEY(a) REFERENCES ref_table(a);') +NOTICE: executing the command locally: SELECT worker_apply_inter_shard_ddl_command (1500112, 'local_commands_test_schema', 1500035, 'local_commands_test_schema', 'ALTER TABLE dist_table ADD CONSTRAINT fkey1 FOREIGN KEY(a) REFERENCES ref_table(a);') +NOTICE: executing the command locally: SELECT worker_apply_inter_shard_ddl_command (1500115, 'local_commands_test_schema', 1500035, 'local_commands_test_schema', 'ALTER TABLE dist_table ADD CONSTRAINT fkey1 FOREIGN KEY(a) REFERENCES ref_table(a);') +NOTICE: executing the command locally: SELECT worker_apply_inter_shard_ddl_command (1500118, 'local_commands_test_schema', 1500035, 'local_commands_test_schema', 'ALTER TABLE dist_table ADD CONSTRAINT fkey1 FOREIGN KEY(a) REFERENCES ref_table(a);') +NOTICE: executing the command locally: SELECT worker_apply_inter_shard_ddl_command (1500121, 'local_commands_test_schema', 1500035, 'local_commands_test_schema', 'ALTER TABLE dist_table ADD CONSTRAINT fkey1 FOREIGN KEY(a) REFERENCES ref_table(a);') +NOTICE: executing the command locally: SELECT worker_apply_inter_shard_ddl_command (1500124, 'local_commands_test_schema', 1500035, 'local_commands_test_schema', 'ALTER TABLE dist_table ADD CONSTRAINT fkey1 FOREIGN KEY(a) REFERENCES ref_table(a);') +NOTICE: executing the command locally: SELECT worker_apply_inter_shard_ddl_command (1500127, 'local_commands_test_schema', 1500035, 'local_commands_test_schema', 'ALTER TABLE dist_table ADD CONSTRAINT fkey1 FOREIGN KEY(a) REFERENCES ref_table(a);') +NOTICE: executing the command locally: SELECT worker_apply_inter_shard_ddl_command (1500130, 'local_commands_test_schema', 1500035, 'local_commands_test_schema', 'ALTER TABLE dist_table ADD CONSTRAINT fkey1 FOREIGN KEY(a) REFERENCES ref_table(a);') + INSERT INTO dist_table VALUES (1); + DELETE FROM ref_table_1 WHERE a=2; +NOTICE: executing the command locally: DELETE FROM local_commands_test_schema.ref_table_1_1500132 ref_table_1 WHERE (a OPERATOR(pg_catalog.=) 2) + -- add another column to dist_table + -- note that we execute below DDL locally as well + ALTER TABLE ref_table ADD b int; +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1500035, 'local_commands_test_schema', 'ALTER TABLE ref_table ADD b int;') + -- define self reference + ALTER TABLE ref_table ADD CONSTRAINT fkey2 FOREIGN KEY(b) REFERENCES ref_table(a); +NOTICE: executing the command locally: SELECT worker_apply_inter_shard_ddl_command (1500035, 'local_commands_test_schema', 1500035, 'local_commands_test_schema', 'ALTER TABLE ref_table ADD CONSTRAINT fkey2 FOREIGN KEY(b) REFERENCES ref_table(a);') + SELECT COUNT(*) FROM ref_table_1, ref_table, dist_table; +NOTICE: executing the command locally: SELECT count(*) AS count FROM ((local_commands_test_schema.dist_table_1500100 dist_table JOIN local_commands_test_schema.ref_table_1_1500132 ref_table_1 ON (true)) JOIN local_commands_test_schema.ref_table_1500035 ref_table ON (true)) WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM ((local_commands_test_schema.dist_table_1500103 dist_table JOIN local_commands_test_schema.ref_table_1_1500132 ref_table_1 ON (true)) JOIN local_commands_test_schema.ref_table_1500035 ref_table ON (true)) WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM ((local_commands_test_schema.dist_table_1500106 dist_table JOIN local_commands_test_schema.ref_table_1_1500132 ref_table_1 ON (true)) JOIN local_commands_test_schema.ref_table_1500035 ref_table ON (true)) WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM ((local_commands_test_schema.dist_table_1500109 dist_table JOIN local_commands_test_schema.ref_table_1_1500132 ref_table_1 ON (true)) JOIN local_commands_test_schema.ref_table_1500035 ref_table ON (true)) WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM ((local_commands_test_schema.dist_table_1500112 dist_table JOIN local_commands_test_schema.ref_table_1_1500132 ref_table_1 ON (true)) JOIN local_commands_test_schema.ref_table_1500035 ref_table ON (true)) WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM ((local_commands_test_schema.dist_table_1500115 dist_table JOIN local_commands_test_schema.ref_table_1_1500132 ref_table_1 ON (true)) JOIN local_commands_test_schema.ref_table_1500035 ref_table ON (true)) WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM ((local_commands_test_schema.dist_table_1500118 dist_table JOIN local_commands_test_schema.ref_table_1_1500132 ref_table_1 ON (true)) JOIN local_commands_test_schema.ref_table_1500035 ref_table ON (true)) WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM ((local_commands_test_schema.dist_table_1500121 dist_table JOIN local_commands_test_schema.ref_table_1_1500132 ref_table_1 ON (true)) JOIN local_commands_test_schema.ref_table_1500035 ref_table ON (true)) WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM ((local_commands_test_schema.dist_table_1500124 dist_table JOIN local_commands_test_schema.ref_table_1_1500132 ref_table_1 ON (true)) JOIN local_commands_test_schema.ref_table_1500035 ref_table ON (true)) WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM ((local_commands_test_schema.dist_table_1500127 dist_table JOIN local_commands_test_schema.ref_table_1_1500132 ref_table_1 ON (true)) JOIN local_commands_test_schema.ref_table_1500035 ref_table ON (true)) WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM ((local_commands_test_schema.dist_table_1500130 dist_table JOIN local_commands_test_schema.ref_table_1_1500132 ref_table_1 ON (true)) JOIN local_commands_test_schema.ref_table_1500035 ref_table ON (true)) WHERE true + count +--------------------------------------------------------------------- + 1 +(1 row) + + -- observe DROP on a self-referencing table also works + DROP TABLE ref_table_1, ref_table, dist_table; +NOTICE: executing the command locally: DROP TABLE IF EXISTS local_commands_test_schema.dist_table_1500100 CASCADE +NOTICE: executing the command locally: DROP TABLE IF EXISTS local_commands_test_schema.dist_table_1500103 CASCADE +NOTICE: executing the command locally: DROP TABLE IF EXISTS local_commands_test_schema.dist_table_1500106 CASCADE +NOTICE: executing the command locally: DROP TABLE IF EXISTS local_commands_test_schema.dist_table_1500109 CASCADE +NOTICE: executing the command locally: DROP TABLE IF EXISTS local_commands_test_schema.dist_table_1500112 CASCADE +NOTICE: executing the command locally: DROP TABLE IF EXISTS local_commands_test_schema.dist_table_1500115 CASCADE +NOTICE: executing the command locally: DROP TABLE IF EXISTS local_commands_test_schema.dist_table_1500118 CASCADE +NOTICE: executing the command locally: DROP TABLE IF EXISTS local_commands_test_schema.dist_table_1500121 CASCADE +NOTICE: executing the command locally: DROP TABLE IF EXISTS local_commands_test_schema.dist_table_1500124 CASCADE +NOTICE: executing the command locally: DROP TABLE IF EXISTS local_commands_test_schema.dist_table_1500127 CASCADE +NOTICE: executing the command locally: DROP TABLE IF EXISTS local_commands_test_schema.dist_table_1500130 CASCADE +NOTICE: executing the command locally: DROP TABLE IF EXISTS local_commands_test_schema.ref_table_1500035 CASCADE +NOTICE: executing the command locally: DROP TABLE IF EXISTS local_commands_test_schema.ref_table_1_1500132 CASCADE + -- show that DROP command is successfull + SELECT tablename FROM pg_tables where schemaname='local_commands_test_schema' ORDER BY tablename; + tablename +--------------------------------------------------------------------- +(0 rows) + +ROLLBACK; +-- add another column to dist_table (should be executed remotely) +ALTER TABLE dist_table ADD b int; +CREATE SCHEMA foo_schema; +-- As SELECT will be executed remotely, ALTER TABLE SET SCHEMA command should alse be executed remotely +BEGIN; + SELECT COUNT(*) FROM dist_table; + count +--------------------------------------------------------------------- + 0 +(1 row) + + ALTER TABLE dist_table SET SCHEMA foo_schema; + -- show that ALTER TABLE SET SCHEMA is successfull + SELECT tablename FROM pg_tables where schemaname='foo_schema' ORDER BY tablename; + tablename +--------------------------------------------------------------------- + dist_table +(1 row) + +ROLLBACK; +-- However, below ALTER TABLE SET SCHEMA command will be executed locally +BEGIN; + ALTER TABLE ref_table SET SCHEMA foo_schema; +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1500035, 'local_commands_test_schema', 'ALTER TABLE local_commands_test_schema.ref_table SET SCHEMA foo_schema;') + -- show that ALTER TABLE SET SCHEMA is successfull + SELECT tablename FROM pg_tables where schemaname='foo_schema' ORDER BY tablename; + tablename +--------------------------------------------------------------------- + ref_table + ref_table_1500035 +(2 rows) + +ROLLBACK; +-- Try a bunch of commands and expect failure at SELECT create_distributed_table +BEGIN; + -- here this SELECT will enforce the whole block for local execution + SELECT COUNT(*) FROM ref_table; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_commands_test_schema.ref_table_1500035 ref_table + count +--------------------------------------------------------------------- + 0 +(1 row) + + -- execute bunch of DDL & DROP commands succesfully + ALTER TABLE dist_table ADD column c int; +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1500100, 'local_commands_test_schema', 'ALTER TABLE dist_table ADD column c int;') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1500103, 'local_commands_test_schema', 'ALTER TABLE dist_table ADD column c int;') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1500106, 'local_commands_test_schema', 'ALTER TABLE dist_table ADD column c int;') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1500109, 'local_commands_test_schema', 'ALTER TABLE dist_table ADD column c int;') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1500112, 'local_commands_test_schema', 'ALTER TABLE dist_table ADD column c int;') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1500115, 'local_commands_test_schema', 'ALTER TABLE dist_table ADD column c int;') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1500118, 'local_commands_test_schema', 'ALTER TABLE dist_table ADD column c int;') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1500121, 'local_commands_test_schema', 'ALTER TABLE dist_table ADD column c int;') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1500124, 'local_commands_test_schema', 'ALTER TABLE dist_table ADD column c int;') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1500127, 'local_commands_test_schema', 'ALTER TABLE dist_table ADD column c int;') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1500130, 'local_commands_test_schema', 'ALTER TABLE dist_table ADD column c int;') + ALTER TABLE dist_table ALTER COLUMN c SET NOT NULL; +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1500100, 'local_commands_test_schema', 'ALTER TABLE dist_table ALTER COLUMN c SET NOT NULL;') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1500103, 'local_commands_test_schema', 'ALTER TABLE dist_table ALTER COLUMN c SET NOT NULL;') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1500106, 'local_commands_test_schema', 'ALTER TABLE dist_table ALTER COLUMN c SET NOT NULL;') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1500109, 'local_commands_test_schema', 'ALTER TABLE dist_table ALTER COLUMN c SET NOT NULL;') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1500112, 'local_commands_test_schema', 'ALTER TABLE dist_table ALTER COLUMN c SET NOT NULL;') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1500115, 'local_commands_test_schema', 'ALTER TABLE dist_table ALTER COLUMN c SET NOT NULL;') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1500118, 'local_commands_test_schema', 'ALTER TABLE dist_table ALTER COLUMN c SET NOT NULL;') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1500121, 'local_commands_test_schema', 'ALTER TABLE dist_table ALTER COLUMN c SET NOT NULL;') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1500124, 'local_commands_test_schema', 'ALTER TABLE dist_table ALTER COLUMN c SET NOT NULL;') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1500127, 'local_commands_test_schema', 'ALTER TABLE dist_table ALTER COLUMN c SET NOT NULL;') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1500130, 'local_commands_test_schema', 'ALTER TABLE dist_table ALTER COLUMN c SET NOT NULL;') + -- as we create table via remote connections, below SELECT create_distributed_table + -- would error out + CREATE TABLE another_dist_table(a int); + SELECT create_distributed_table('another_dist_table', 'a'); +ERROR: cannot execute command because a local execution has accessed a placement in the transaction +COMMIT; +-- cleanup at exit +DROP SCHEMA local_commands_test_schema CASCADE; +NOTICE: drop cascades to 16 other objects +DROP SCHEMA foo_schema; +SELECT 1 FROM master_set_node_property('localhost', :master_port, 'shouldhaveshards', false); + ?column? +--------------------------------------------------------------------- + 1 +(1 row) + diff --git a/src/test/regress/multi_schedule b/src/test/regress/multi_schedule index 76b4a112b..21d1ff915 100644 --- a/src/test/regress/multi_schedule +++ b/src/test/regress/multi_schedule @@ -51,7 +51,7 @@ test: multi_row_insert test: insert_select_connection_leak # --------- -# at the end of the regression tests regaring recursively planned modifications +# at the end of the regression tests regarding recursively planned modifications # ensure that we don't leak any intermediate results # This test should not run in parallel with any other tests # --------- @@ -282,6 +282,7 @@ test: multi_reference_table test: foreign_key_to_reference_table test: replicate_reference_tables_to_coordinator test: coordinator_shouldhaveshards +test: local_shard_utility_command_execution test: remove_coordinator diff --git a/src/test/regress/sql/local_shard_utility_command_execution.sql b/src/test/regress/sql/local_shard_utility_command_execution.sql new file mode 100644 index 000000000..a403aba25 --- /dev/null +++ b/src/test/regress/sql/local_shard_utility_command_execution.sql @@ -0,0 +1,298 @@ +-- This tests file includes tests for local execution of utility commands. +-- For now, this file includes tests only for local execution of +-- `TRUNCATE/DROP/DDL` commands for all kinds of distributed tables from +-- the coordinator node having regular distributed tables' shards +-- (shouldHaveShards = on) and having reference table placements in it. + +\set VERBOSITY terse + +SET citus.next_shard_id TO 1500000; +SET citus.shard_replication_factor TO 1; +SET citus.enable_local_execution TO ON; +SET citus.shard_COUNT TO 32; +SET citus.log_local_commands TO ON; + +CREATE SCHEMA local_commands_test_schema; +SET search_path TO local_commands_test_schema; + +-- let coordinator have distributed table shards/placements +SELECT master_add_node('localhost', :master_port, groupId => 0); +SELECT master_set_node_property('localhost', :master_port, 'shouldhaveshards', true); + +----------------------------------------- +------ local execution of TRUNCATE ------ +----------------------------------------- + +CREATE TABLE ref_table (a int primary key); +SELECT create_reference_table('ref_table'); + +CREATE TABLE dist_table(a int); +SELECT create_distributed_table('dist_table', 'a'); + +ALTER TABLE dist_table ADD CONSTRAINT fkey FOREIGN KEY(a) REFERENCES ref_table(a); + +-- insert some data +INSERT INTO ref_table VALUES(1); +INSERT INTO dist_table VALUES(1); + +-- Currently, we support local execution of TRUNCATE commands for all kinds +-- Hence, cascading to distributed tables wouldn't be a problem even in the +-- case that coordinator have some local distributed table shards. +TRUNCATE ref_table CASCADE; + +-- show that TRUNCATE is successfull +SELECT COUNT(*) FROM ref_table, dist_table; + +-- insert some data +INSERT INTO ref_table VALUES(1); +INSERT INTO dist_table VALUES(1); + +-- As SELECT accesses local placements of reference table, TRUNCATE would also +-- be forced to local execution even if they operate on different tables. +BEGIN; + SELECT COUNT(*) FROM ref_table; + TRUNCATE dist_table; +COMMIT; + +-- show that TRUNCATE is successfull +SELECT COUNT(*) FROM dist_table; + +-- insert some data +INSERT INTO ref_table VALUES(2); +INSERT INTO dist_table VALUES(2); + +-- However, SELECT would access local placements via remote connections +-- for regular distributed tables, TRUNCATE would also be executed remotely. +BEGIN; + SELECT COUNT(*) FROM dist_table; + TRUNCATE dist_table; +COMMIT; + +-- show that TRUNCATE is successfull +SELECT COUNT(*) FROM dist_table; + +-- insert some data +INSERT INTO ref_table VALUES(3); +INSERT INTO dist_table VALUES(3); + +-- TRUNCATE on dist_table (note that: again no cascade here) would +-- just be handled via remote executions even on its local shards +TRUNCATE dist_table; + +-- show that TRUNCATE is successfull +SELECT COUNT(*) FROM dist_table; + +-- insert some data +INSERT INTO ref_table VALUES(4); + +-- However, creating a dist. table is handled by remote connections. +-- Hence, the commands following it (INSERT & TRUNCATE) would also be +-- handled remotely. +BEGIN; + CREATE TABLE ref_table_1(a int); + SELECT create_reference_table('ref_table_1'); + + -- insert some data + INSERT INTO ref_table_1 VALUES(5); + + TRUNCATE ref_table_1; +COMMIT; + +-- show that TRUNCATE is successfull +SELECT COUNT(*) FROM ref_table_1; + +-- However, as SELECT would access local placements via remote parallel +-- connections for regular distributed tables, below TRUNCATE would error +-- out +BEGIN; + SELECT COUNT(*) FROM dist_table; + TRUNCATE ref_table CASCADE; +COMMIT; + +-- insert some data +INSERT INTO ref_table VALUES(7); +INSERT INTO dist_table VALUES(7); + +-- we can TRUNCATE those two tables within the same command +TRUNCATE ref_table, dist_table; + +-- show that TRUNCATE is successfull +SELECT COUNT(*) FROM ref_table, dist_table; + +------------------------------------- +------ local execution of DROP ------ +------------------------------------- + +-- droping just the referenced table would error out as dist_table references it +DROP TABLE ref_table; + +-- drop those two tables via remote execution +DROP TABLE ref_table, dist_table; + +-- drop the other standalone table locally +DROP TABLE ref_table_1; + +-- show that DROP commands are successfull +SELECT tablename FROM pg_tables where schemaname='local_commands_test_schema' ORDER BY tablename; + +CREATE TABLE ref_table (a int primary key); +SELECT create_reference_table('ref_table'); + +-- We execute SELECT command within the below block locally. +-- Hence we should execute the DROP command locally as well. +BEGIN; + SELECT COUNT(*) FROM ref_table; + DROP TABLE ref_table; +COMMIT; + +CREATE TABLE ref_table (a int primary key); +SELECT create_reference_table('ref_table'); + +CREATE TABLE dist_table(a int); +SELECT create_distributed_table('dist_table', 'a'); + +ALTER TABLE dist_table ADD CONSTRAINT fkey FOREIGN KEY(a) REFERENCES ref_table(a); + +-- As both commands will prefer remote exeuction, TRUNCATE would be aware of +-- dist_table is dropped. Hence, below block should not be effective as TRUNCATE +-- will error out. +BEGIN; + DROP TABLE dist_table CASCADE; + TRUNCATE dist_table; +COMMIT; + +-- show that DROP command is rollback'd successfully (should print 1) +SELECT 1 FROM pg_tables where tablename='dist_table'; + +-- As SELECT will be executed remotely, the DROP command should also be executed +-- remotely to prevent possible self-deadlocks & inconsistencies. +-- FIXME: we have a known bug for below case described in +-- https://github.com/citusdata/citus/issues/3526. Hence, commented out as it could +-- randomly fall into distributed deadlocks +--BEGIN; +-- SELECT COUNT(*) FROM dist_table; +-- DROP TABLE dist_table; +--END; + +-- As SELECT will be executed remotely, the DROP command below should also be +-- executed remotely. +CREATE TABLE another_dist_table(a int); +SELECT create_distributed_table('another_dist_table', 'a'); + +BEGIN; + SELECT COUNT(*) FROM another_dist_table; + DROP TABLE another_dist_table; +COMMIT; + +-- show that DROP command is committed successfully +SELECT 1 FROM pg_tables where tablename='another_dist_table'; + +-- below DROP will be executed remotely. +DROP TABLE dist_table; + +-- show that DROP command is successfull +SELECT 1 FROM pg_tables where tablename='dist_table'; + +CREATE TABLE dist_table(a int); +SELECT create_distributed_table('dist_table', 'a'); + +ALTER TABLE dist_table ADD CONSTRAINT fkey FOREIGN KEY(a) REFERENCES ref_table(a); + +-- as SELECT on ref_table will be executed locally, the SELECT and DROP following +-- it would also be executed locally +BEGIN; + SELECT COUNT(*) FROM ref_table; + DROP TABLE dist_table CASCADE; +ROLLBACK; + +-- show that DROP command is rollback'd successfully (should print 1) +SELECT 1 FROM pg_tables where tablename='dist_table'; + +--------------------------------------------- +------ local execution of DDL commands ------ +--------------------------------------------- + +-- try some complicated CASCADE cases along with DDL commands + +CREATE TABLE ref_table_1(a int primary key); +SELECT create_reference_table('ref_table_1'); + +-- below block should execute successfully +BEGIN; + SELECT COUNT(*) FROM ref_table; + + -- as SELECT above runs locally and as now we support local execution of DDL commands, + -- below DDL should be able to define foreign key constraint successfully + ALTER TABLE ref_table ADD CONSTRAINT fkey FOREIGN KEY(a) REFERENCES ref_table_1(a); + + -- insert some data + INSERT INTO ref_table_1 VALUES (1); + INSERT INTO ref_table_1 VALUES (2); + INSERT INTO ref_table VALUES (1); + + -- chain foreign key constraints + -- local execution should be observed here as well + ALTER TABLE dist_table ADD CONSTRAINT fkey1 FOREIGN KEY(a) REFERENCES ref_table(a); + + INSERT INTO dist_table VALUES (1); + + DELETE FROM ref_table_1 WHERE a=2; + + -- add another column to dist_table + -- note that we execute below DDL locally as well + ALTER TABLE ref_table ADD b int; + + -- define self reference + ALTER TABLE ref_table ADD CONSTRAINT fkey2 FOREIGN KEY(b) REFERENCES ref_table(a); + + SELECT COUNT(*) FROM ref_table_1, ref_table, dist_table; + + -- observe DROP on a self-referencing table also works + DROP TABLE ref_table_1, ref_table, dist_table; + + -- show that DROP command is successfull + SELECT tablename FROM pg_tables where schemaname='local_commands_test_schema' ORDER BY tablename; +ROLLBACK; + +-- add another column to dist_table (should be executed remotely) +ALTER TABLE dist_table ADD b int; + +CREATE SCHEMA foo_schema; + +-- As SELECT will be executed remotely, ALTER TABLE SET SCHEMA command should alse be executed remotely +BEGIN; + SELECT COUNT(*) FROM dist_table; + + ALTER TABLE dist_table SET SCHEMA foo_schema; + + -- show that ALTER TABLE SET SCHEMA is successfull + SELECT tablename FROM pg_tables where schemaname='foo_schema' ORDER BY tablename; +ROLLBACK; + +-- However, below ALTER TABLE SET SCHEMA command will be executed locally +BEGIN; + ALTER TABLE ref_table SET SCHEMA foo_schema; + + -- show that ALTER TABLE SET SCHEMA is successfull + SELECT tablename FROM pg_tables where schemaname='foo_schema' ORDER BY tablename; +ROLLBACK; + +-- Try a bunch of commands and expect failure at SELECT create_distributed_table +BEGIN; + -- here this SELECT will enforce the whole block for local execution + SELECT COUNT(*) FROM ref_table; + + -- execute bunch of DDL & DROP commands succesfully + ALTER TABLE dist_table ADD column c int; + ALTER TABLE dist_table ALTER COLUMN c SET NOT NULL; + + -- as we create table via remote connections, below SELECT create_distributed_table + -- would error out + CREATE TABLE another_dist_table(a int); + SELECT create_distributed_table('another_dist_table', 'a'); +COMMIT; + +-- cleanup at exit +DROP SCHEMA local_commands_test_schema CASCADE; +DROP SCHEMA foo_schema; +SELECT 1 FROM master_set_node_property('localhost', :master_port, 'shouldhaveshards', false);