-- -- MULTI_TENANT_ISOLATION -- -- Tests tenant isolation feature -- ALTER SEQUENCE pg_catalog.pg_dist_shardid_seq RESTART 1230000; SELECT nextval('pg_catalog.pg_dist_placement_placementid_seq') AS last_placement_id \gset ALTER SEQUENCE pg_catalog.pg_dist_placement_placementid_seq RESTART 100000; CREATE SCHEMA "Tenant Isolation"; SET search_path to "Tenant Isolation"; CREATE ROLE mx_isolation_role_ent WITH LOGIN; GRANT ALL ON SCHEMA "Tenant Isolation", public TO mx_isolation_role_ent; -- connect with this new role \c - mx_isolation_role_ent - :master_port SET search_path to "Tenant Isolation"; SET citus.shard_replication_factor TO 1; SET citus.shard_count to 2; CREATE TABLE lineitem_streaming ( l_orderkey bigint not null, l_partkey integer not null, l_suppkey integer not null, l_linenumber integer not null, l_quantity decimal(15, 2) not null, l_extendedprice decimal(15, 2) not null, l_discount decimal(15, 2) not null, l_tax decimal(15, 2) not null, l_returnflag char(1) not null, l_linestatus char(1) not null, l_shipdate date not null, l_commitdate date not null, l_receiptdate date not null, l_shipinstruct char(25) not null, l_shipmode char(10) not null, l_comment varchar(44) not null); SELECT create_distributed_table('lineitem_streaming', 'l_orderkey'); create_distributed_table --------------------------------------------------------------------- (1 row) CREATE TABLE orders_streaming ( o_orderkey bigint not null primary key, o_custkey integer not null, o_orderstatus char(1) not null, o_totalprice decimal(15,2) not null, o_orderdate date not null, o_orderpriority char(15) not null, o_clerk char(15) not null, o_shippriority integer not null, o_comment varchar(79) not null); SELECT create_distributed_table('orders_streaming', 'o_orderkey'); create_distributed_table --------------------------------------------------------------------- (1 row) \COPY lineitem_streaming FROM STDIN WITH DELIMITER '|' \COPY orders_streaming FROM STDIN WITH DELIMITER '|' ALTER TABLE lineitem_streaming ADD CONSTRAINT test_constraint FOREIGN KEY(l_orderkey) REFERENCES orders_streaming(o_orderkey); -- test failing foreign constraints \COPY lineitem_streaming FROM STDIN WITH DELIMITER '|' ERROR: insert or update on table "lineitem_streaming_1230001" violates foreign key constraint "test_constraint_1230001" DETAIL: Key (l_orderkey)=(128) is not present in table "orders_streaming_1230003". -- tests for cluster health SELECT count(*) FROM lineitem_streaming; count --------------------------------------------------------------------- 22 (1 row) SELECT count(*) FROM orders_streaming; count --------------------------------------------------------------------- 7 (1 row) SELECT l_orderkey, sum(l_extendedprice * (1 - l_discount)) as revenue, o_orderdate FROM orders_streaming, lineitem_streaming WHERE l_orderkey = o_orderkey GROUP BY l_orderkey, o_orderdate ORDER BY revenue DESC, o_orderdate; l_orderkey | revenue | o_orderdate --------------------------------------------------------------------- 100 | 181042.2683 | 02-28-1998 102 | 159639.9677 | 05-09-1997 101 | 124074.5328 | 03-17-1996 103 | 119741.5469 | 06-20-1996 99 | 109604.3256 | 03-13-1994 -1995148554 | 16890.6816 | 05-08-1995 -1686493264 | 1988.7134 | 09-05-1997 (7 rows) -- Checks to see if metadata and data are isolated properly. If there are problems in -- metadata and/or data on workers, these queries should return different results below -- after tenant isolation operations are applied. SELECT count(*) FROM lineitem_streaming WHERE l_orderkey = 99; count --------------------------------------------------------------------- 4 (1 row) SELECT count(*) FROM lineitem_streaming WHERE l_orderkey = 100; count --------------------------------------------------------------------- 5 (1 row) SELECT count(*) FROM lineitem_streaming WHERE l_orderkey = 101; count --------------------------------------------------------------------- 3 (1 row) SELECT count(*) FROM lineitem_streaming WHERE l_orderkey = 102; count --------------------------------------------------------------------- 4 (1 row) SELECT count(*) FROM lineitem_streaming WHERE l_orderkey = 103; count --------------------------------------------------------------------- 4 (1 row) SELECT count(*) FROM orders_streaming WHERE o_orderkey = 99; count --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM orders_streaming WHERE o_orderkey = 100; count --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM orders_streaming WHERE o_orderkey = 101; count --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM orders_streaming WHERE o_orderkey = 102; count --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM orders_streaming WHERE o_orderkey = 103; count --------------------------------------------------------------------- 1 (1 row) SELECT * FROM pg_dist_shard WHERE logicalrelid = 'lineitem_streaming'::regclass OR logicalrelid = 'orders_streaming'::regclass ORDER BY shardminvalue::BIGINT, logicalrelid; logicalrelid | shardid | shardstorage | shardminvalue | shardmaxvalue --------------------------------------------------------------------- lineitem_streaming | 1230000 | t | -2147483648 | -1 orders_streaming | 1230002 | t | -2147483648 | -1 lineitem_streaming | 1230001 | t | 0 | 2147483647 orders_streaming | 1230003 | t | 0 | 2147483647 (4 rows) -- check without cascade option SELECT isolate_tenant_to_new_shard('lineitem_streaming', 100, shard_transfer_mode => 'force_logical'); ERROR: cannot isolate tenant because "lineitem_streaming" has colocated tables HINT: Use CASCADE option to isolate tenants for the colocated tables too. Example usage: isolate_tenant_to_new_shard('lineitem_streaming', '100', 'CASCADE') -- check with an input not castable to bigint SELECT isolate_tenant_to_new_shard('lineitem_streaming', 'abc', 'CASCADE', shard_transfer_mode => 'force_logical'); ERROR: invalid input syntax for type bigint: "abc" SELECT isolate_tenant_to_new_shard('lineitem_streaming', 100, 'CASCADE', shard_transfer_mode => 'force_logical'); isolate_tenant_to_new_shard --------------------------------------------------------------------- 1230005 (1 row) SELECT isolate_tenant_to_new_shard('lineitem_streaming', 101, 'CASCADE', shard_transfer_mode => 'force_logical'); isolate_tenant_to_new_shard --------------------------------------------------------------------- 1230011 (1 row) -- add an explain check to see if we hit the new isolated shard EXPLAIN (COSTS false) SELECT count(*) FROM lineitem_streaming WHERE l_orderkey = 101; QUERY PLAN --------------------------------------------------------------------- Custom Scan (Citus Adaptive) Task Count: 1 Tasks Shown: All -> Task Node: host=localhost port=xxxxx dbname=regression -> Aggregate -> Seq Scan on lineitem_streaming_1230011 lineitem_streaming Filter: (l_orderkey = 101) (8 rows) -- create an MX node \c - postgres - :master_port SELECT start_metadata_sync_to_node('localhost', :worker_1_port); start_metadata_sync_to_node --------------------------------------------------------------------- (1 row) \c - mx_isolation_role_ent - :master_port SET search_path to "Tenant Isolation"; -- test a failing transaction block BEGIN; SELECT isolate_tenant_to_new_shard('orders_streaming', 102, 'CASCADE', shard_transfer_mode => 'force_logical'); isolate_tenant_to_new_shard --------------------------------------------------------------------- 1230020 (1 row) SELECT isolate_tenant_to_new_shard('lineitem_streaming', 102, 'CASCADE', shard_transfer_mode => 'force_logical'); ERROR: table lineitem_streaming has already been isolated for the given value COMMIT; -- test a rollback transaction block BEGIN; SELECT isolate_tenant_to_new_shard('orders_streaming', 102, 'CASCADE', shard_transfer_mode => 'force_logical'); isolate_tenant_to_new_shard --------------------------------------------------------------------- 1230026 (1 row) SELECT isolate_tenant_to_new_shard('orders_streaming', 103, 'CASCADE', shard_transfer_mode => 'force_logical'); ERROR: multiple shard movements/splits via logical replication in the same transaction is currently not supported ROLLBACK; -- test a succesfull transaction block BEGIN; SELECT isolate_tenant_to_new_shard('orders_streaming', 102, 'CASCADE', shard_transfer_mode => 'force_logical'); isolate_tenant_to_new_shard --------------------------------------------------------------------- 1230032 (1 row) COMMIT; SELECT isolate_tenant_to_new_shard('orders_streaming', 103, 'CASCADE', shard_transfer_mode => 'force_logical'); isolate_tenant_to_new_shard --------------------------------------------------------------------- 1230038 (1 row) SELECT isolate_tenant_to_new_shard('lineitem_streaming', 100, 'CASCADE', shard_transfer_mode => 'force_logical'); ERROR: table lineitem_streaming has already been isolated for the given value SELECT isolate_tenant_to_new_shard('orders_streaming', 101, 'CASCADE', shard_transfer_mode => 'force_logical'); ERROR: table orders_streaming has already been isolated for the given value -- test corner cases: hash(-1995148554) = -2147483648 and hash(-1686493264) = 2147483647 SELECT isolate_tenant_to_new_shard('lineitem_streaming', -1995148554, 'CASCADE', shard_transfer_mode => 'force_logical'); isolate_tenant_to_new_shard --------------------------------------------------------------------- 1230040 (1 row) SELECT isolate_tenant_to_new_shard('orders_streaming', -1686493264, 'CASCADE', shard_transfer_mode => 'force_logical'); isolate_tenant_to_new_shard --------------------------------------------------------------------- 1230047 (1 row) SELECT count(*) FROM orders_streaming WHERE o_orderkey = -1995148554; count --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM orders_streaming WHERE o_orderkey = -1686493264; count --------------------------------------------------------------------- 1 (1 row) -- tests for cluster health SELECT count(*) FROM lineitem_streaming; count --------------------------------------------------------------------- 22 (1 row) SELECT count(*) FROM orders_streaming; count --------------------------------------------------------------------- 7 (1 row) SELECT l_orderkey, sum(l_extendedprice * (1 - l_discount)) as revenue, o_orderdate FROM orders_streaming, lineitem_streaming WHERE l_orderkey = o_orderkey GROUP BY l_orderkey, o_orderdate ORDER BY revenue DESC, o_orderdate; l_orderkey | revenue | o_orderdate --------------------------------------------------------------------- 100 | 181042.2683 | 02-28-1998 102 | 159639.9677 | 05-09-1997 101 | 124074.5328 | 03-17-1996 103 | 119741.5469 | 06-20-1996 99 | 109604.3256 | 03-13-1994 -1995148554 | 16890.6816 | 05-08-1995 -1686493264 | 1988.7134 | 09-05-1997 (7 rows) SELECT count(*) FROM lineitem_streaming WHERE l_orderkey = 99; count --------------------------------------------------------------------- 4 (1 row) SELECT count(*) FROM lineitem_streaming WHERE l_orderkey = 100; count --------------------------------------------------------------------- 5 (1 row) SELECT count(*) FROM lineitem_streaming WHERE l_orderkey = 101; count --------------------------------------------------------------------- 3 (1 row) SELECT count(*) FROM lineitem_streaming WHERE l_orderkey = 102; count --------------------------------------------------------------------- 4 (1 row) SELECT count(*) FROM lineitem_streaming WHERE l_orderkey = 103; count --------------------------------------------------------------------- 4 (1 row) SELECT count(*) FROM orders_streaming WHERE o_orderkey = 99; count --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM orders_streaming WHERE o_orderkey = 100; count --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM orders_streaming WHERE o_orderkey = 101; count --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM orders_streaming WHERE o_orderkey = 102; count --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM orders_streaming WHERE o_orderkey = 103; count --------------------------------------------------------------------- 1 (1 row) SELECT * FROM pg_dist_shard WHERE logicalrelid = 'lineitem_streaming'::regclass OR logicalrelid = 'orders_streaming'::regclass ORDER BY shardminvalue::BIGINT, logicalrelid; logicalrelid | shardid | shardstorage | shardminvalue | shardmaxvalue --------------------------------------------------------------------- lineitem_streaming | 1230040 | t | -2147483648 | -2147483648 orders_streaming | 1230042 | t | -2147483648 | -2147483648 lineitem_streaming | 1230041 | t | -2147483647 | -136164586 orders_streaming | 1230043 | t | -2147483647 | -136164586 lineitem_streaming | 1230035 | t | -136164585 | -136164585 orders_streaming | 1230038 | t | -136164585 | -136164585 lineitem_streaming | 1230036 | t | -136164584 | -85071815 orders_streaming | 1230039 | t | -136164584 | -85071815 lineitem_streaming | 1230011 | t | -85071814 | -85071814 orders_streaming | 1230014 | t | -85071814 | -85071814 lineitem_streaming | 1230012 | t | -85071813 | -1 orders_streaming | 1230015 | t | -85071813 | -1 lineitem_streaming | 1230004 | t | 0 | 108199380 orders_streaming | 1230007 | t | 0 | 108199380 lineitem_streaming | 1230005 | t | 108199381 | 108199381 orders_streaming | 1230008 | t | 108199381 | 108199381 lineitem_streaming | 1230028 | t | 108199382 | 412880111 orders_streaming | 1230031 | t | 108199382 | 412880111 lineitem_streaming | 1230029 | t | 412880112 | 412880112 orders_streaming | 1230032 | t | 412880112 | 412880112 lineitem_streaming | 1230044 | t | 412880113 | 2147483646 orders_streaming | 1230046 | t | 412880113 | 2147483646 lineitem_streaming | 1230045 | t | 2147483647 | 2147483647 orders_streaming | 1230047 | t | 2147483647 | 2147483647 (24 rows) SELECT * FROM pg_dist_shard_placement WHERE shardid >= 1230000 ORDER BY nodeport, shardid; shardid | shardstate | shardlength | nodename | nodeport | placementid --------------------------------------------------------------------- 1230011 | 1 | 0 | localhost | 57637 | 100011 1230012 | 1 | 0 | localhost | 57637 | 100012 1230014 | 1 | 0 | localhost | 57637 | 100014 1230015 | 1 | 0 | localhost | 57637 | 100015 1230035 | 1 | 0 | localhost | 57637 | 100035 1230036 | 1 | 0 | localhost | 57637 | 100036 1230038 | 1 | 0 | localhost | 57637 | 100038 1230039 | 1 | 0 | localhost | 57637 | 100039 1230040 | 1 | 0 | localhost | 57637 | 100040 1230041 | 1 | 0 | localhost | 57637 | 100041 1230042 | 1 | 0 | localhost | 57637 | 100042 1230043 | 1 | 0 | localhost | 57637 | 100043 1230004 | 1 | 0 | localhost | 57638 | 100004 1230005 | 1 | 0 | localhost | 57638 | 100005 1230007 | 1 | 0 | localhost | 57638 | 100007 1230008 | 1 | 0 | localhost | 57638 | 100008 1230028 | 1 | 0 | localhost | 57638 | 100028 1230029 | 1 | 0 | localhost | 57638 | 100029 1230031 | 1 | 0 | localhost | 57638 | 100031 1230032 | 1 | 0 | localhost | 57638 | 100032 1230044 | 1 | 0 | localhost | 57638 | 100044 1230045 | 1 | 0 | localhost | 57638 | 100045 1230046 | 1 | 0 | localhost | 57638 | 100046 1230047 | 1 | 0 | localhost | 57638 | 100047 (24 rows) -- test failing foreign constraints after multiple tenant isolation \COPY lineitem_streaming FROM STDIN WITH DELIMITER '|' ERROR: insert or update on table "lineitem_streaming_1230044" violates foreign key constraint "test_constraint_1230044" DETAIL: Key (l_orderkey)=(128) is not present in table "orders_streaming_1230046". \c - postgres - :master_port CALL pg_catalog.citus_cleanup_orphaned_resources(); NOTICE: cleaned up 30 orphaned resources -- connect to the worker node with metadata \c - mx_isolation_role_ent - :worker_1_port SET search_path to "Tenant Isolation"; -- check mx tables SELECT count(*) FROM lineitem_streaming; count --------------------------------------------------------------------- 22 (1 row) SELECT count(*) FROM orders_streaming; count --------------------------------------------------------------------- 7 (1 row) SELECT l_orderkey, sum(l_extendedprice * (1 - l_discount)) as revenue, o_orderdate FROM orders_streaming, lineitem_streaming WHERE l_orderkey = o_orderkey GROUP BY l_orderkey, o_orderdate ORDER BY revenue DESC, o_orderdate; l_orderkey | revenue | o_orderdate --------------------------------------------------------------------- 100 | 181042.2683 | 02-28-1998 102 | 159639.9677 | 05-09-1997 101 | 124074.5328 | 03-17-1996 103 | 119741.5469 | 06-20-1996 99 | 109604.3256 | 03-13-1994 -1995148554 | 16890.6816 | 05-08-1995 -1686493264 | 1988.7134 | 09-05-1997 (7 rows) -- check shards SET citus.override_table_visibility TO false; \d List of relations Schema | Name | Type | Owner --------------------------------------------------------------------- Tenant Isolation | lineitem_streaming | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230011 | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230012 | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230035 | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230036 | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230040 | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230041 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230014 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230015 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230038 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230039 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230042 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230043 | table | mx_isolation_role_ent (14 rows) \c - postgres - :worker_1_port SET search_path to "Tenant Isolation"; SELECT "Column", "Type", "Modifiers" FROM public.table_desc WHERE relid='orders_streaming_1230039'::regclass; Column | Type | Modifiers --------------------------------------------------------------------- o_orderkey | bigint | not null o_custkey | integer | not null o_orderstatus | character(1) | not null o_totalprice | numeric(15,2) | not null o_orderdate | date | not null o_orderpriority | character(15) | not null o_clerk | character(15) | not null o_shippriority | integer | not null o_comment | character varying(79) | not null (9 rows) \c - mx_isolation_role_ent - :worker_1_port SET search_path to "Tenant Isolation"; -- check MX metadata SELECT * FROM pg_dist_shard WHERE logicalrelid = 'lineitem_streaming'::regclass OR logicalrelid = 'orders_streaming'::regclass ORDER BY shardminvalue::BIGINT, logicalrelid; logicalrelid | shardid | shardstorage | shardminvalue | shardmaxvalue --------------------------------------------------------------------- lineitem_streaming | 1230040 | t | -2147483648 | -2147483648 orders_streaming | 1230042 | t | -2147483648 | -2147483648 lineitem_streaming | 1230041 | t | -2147483647 | -136164586 orders_streaming | 1230043 | t | -2147483647 | -136164586 lineitem_streaming | 1230035 | t | -136164585 | -136164585 orders_streaming | 1230038 | t | -136164585 | -136164585 lineitem_streaming | 1230036 | t | -136164584 | -85071815 orders_streaming | 1230039 | t | -136164584 | -85071815 lineitem_streaming | 1230011 | t | -85071814 | -85071814 orders_streaming | 1230014 | t | -85071814 | -85071814 lineitem_streaming | 1230012 | t | -85071813 | -1 orders_streaming | 1230015 | t | -85071813 | -1 lineitem_streaming | 1230004 | t | 0 | 108199380 orders_streaming | 1230007 | t | 0 | 108199380 lineitem_streaming | 1230005 | t | 108199381 | 108199381 orders_streaming | 1230008 | t | 108199381 | 108199381 lineitem_streaming | 1230028 | t | 108199382 | 412880111 orders_streaming | 1230031 | t | 108199382 | 412880111 lineitem_streaming | 1230029 | t | 412880112 | 412880112 orders_streaming | 1230032 | t | 412880112 | 412880112 lineitem_streaming | 1230044 | t | 412880113 | 2147483646 orders_streaming | 1230046 | t | 412880113 | 2147483646 lineitem_streaming | 1230045 | t | 2147483647 | 2147483647 orders_streaming | 1230047 | t | 2147483647 | 2147483647 (24 rows) -- return to master node \c - mx_isolation_role_ent - :master_port -- test a distribution type which does not have a sql hash function SET search_path to "Tenant Isolation"; SET citus.shard_replication_factor TO 2; SET citus.shard_count to 2; CREATE TABLE lineitem_date ( l_orderkey bigint not null, l_partkey integer not null, l_suppkey integer not null, l_linenumber integer not null, l_quantity decimal(15, 2) not null, l_extendedprice decimal(15, 2) not null, l_discount decimal(15, 2) not null, l_tax decimal(15, 2) not null, l_returnflag char(1) not null, l_linestatus char(1) not null, l_shipdate date not null, l_commitdate date not null, l_receiptdate date not null, l_shipinstruct char(25) not null, l_shipmode char(10) not null, l_comment varchar(44) not null); SELECT create_distributed_table('lineitem_date', 'l_shipdate'); create_distributed_table --------------------------------------------------------------------- (1 row) \COPY lineitem_date FROM STDIN WITH DELIMITER '|' SELECT count(*) FROM lineitem_date; count --------------------------------------------------------------------- 4 (1 row) SELECT count(*) FROM lineitem_date WHERE l_shipdate = '1998-05-26'; count --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM lineitem_date WHERE l_shipdate = '1997-07-30'; count --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM lineitem_date WHERE l_shipdate = '1998-01-15'; count --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM lineitem_date WHERE l_shipdate = '1997-08-08'; count --------------------------------------------------------------------- 1 (1 row) SELECT isolate_tenant_to_new_shard('lineitem_date', '1998-05-26', shard_transfer_mode => 'force_logical'); ERROR: cannot isolate tenants when using shard replication SELECT isolate_tenant_to_new_shard('lineitem_date', '1997-07-30', shard_transfer_mode => 'force_logical'); ERROR: cannot isolate tenants when using shard replication SELECT isolate_tenant_to_new_shard('lineitem_date', '1998-01-15', shard_transfer_mode => 'force_logical'); ERROR: cannot isolate tenants when using shard replication SELECT count(*) FROM lineitem_date; count --------------------------------------------------------------------- 4 (1 row) SELECT count(*) FROM lineitem_date WHERE l_shipdate = '1998-05-26'; count --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM lineitem_date WHERE l_shipdate = '1997-07-30'; count --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM lineitem_date WHERE l_shipdate = '1998-01-15'; count --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM lineitem_date WHERE l_shipdate = '1997-08-08'; count --------------------------------------------------------------------- 1 (1 row) -- test with text distribution column (because of collations) SET citus.shard_replication_factor TO 1; CREATE TABLE text_column (tenant_id text, value jsonb); INSERT INTO text_column VALUES ('hello','{}'); SELECT create_distributed_table('text_column','tenant_id'); NOTICE: Copying data from local table... NOTICE: copying the data has completed DETAIL: The local data in the table is no longer visible, but is still on disk. HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$"Tenant Isolation".text_column$$) create_distributed_table --------------------------------------------------------------------- (1 row) SELECT isolate_tenant_to_new_shard('text_column', 'hello', shard_transfer_mode => 'force_logical'); isolate_tenant_to_new_shard --------------------------------------------------------------------- 1230053 (1 row) SELECT * FROM text_column; tenant_id | value --------------------------------------------------------------------- hello | {} (1 row) CALL pg_catalog.citus_cleanup_orphaned_resources(); NOTICE: cleaned up 1 orphaned resources -- test with invalid shard placements \c - postgres - :master_port SET search_path to "Tenant Isolation"; UPDATE pg_dist_shard_placement SET shardstate = 3 WHERE nodeport = :worker_1_port; SELECT isolate_tenant_to_new_shard('lineitem_date', '1997-08-08', shard_transfer_mode => 'force_logical'); ERROR: cannot isolate tenant because relation "lineitem_date" has an inactive shard placement for the shard xxxxx UPDATE pg_dist_shard_placement SET shardstate = 1 WHERE nodeport = :worker_1_port; \c - mx_isolation_role_ent - :master_port SET search_path to "Tenant Isolation"; DROP TABLE lineitem_date; -- test on append distributed table CREATE TABLE test_append ( tenant_id integer ); SELECT create_distributed_table('test_append', 'tenant_id', 'append'); create_distributed_table --------------------------------------------------------------------- (1 row) SELECT isolate_tenant_to_new_shard('test_append', 100, shard_transfer_mode => 'force_logical'); ERROR: cannot isolate tenant because tenant isolation is only support for hash distributed tables -- check metadata for comparison SELECT * FROM pg_dist_shard WHERE logicalrelid = 'lineitem_streaming'::regclass OR logicalrelid = 'orders_streaming'::regclass ORDER BY shardminvalue::BIGINT, logicalrelid; logicalrelid | shardid | shardstorage | shardminvalue | shardmaxvalue --------------------------------------------------------------------- lineitem_streaming | 1230040 | t | -2147483648 | -2147483648 orders_streaming | 1230042 | t | -2147483648 | -2147483648 lineitem_streaming | 1230041 | t | -2147483647 | -136164586 orders_streaming | 1230043 | t | -2147483647 | -136164586 lineitem_streaming | 1230035 | t | -136164585 | -136164585 orders_streaming | 1230038 | t | -136164585 | -136164585 lineitem_streaming | 1230036 | t | -136164584 | -85071815 orders_streaming | 1230039 | t | -136164584 | -85071815 lineitem_streaming | 1230011 | t | -85071814 | -85071814 orders_streaming | 1230014 | t | -85071814 | -85071814 lineitem_streaming | 1230012 | t | -85071813 | -1 orders_streaming | 1230015 | t | -85071813 | -1 lineitem_streaming | 1230004 | t | 0 | 108199380 orders_streaming | 1230007 | t | 0 | 108199380 lineitem_streaming | 1230005 | t | 108199381 | 108199381 orders_streaming | 1230008 | t | 108199381 | 108199381 lineitem_streaming | 1230028 | t | 108199382 | 412880111 orders_streaming | 1230031 | t | 108199382 | 412880111 lineitem_streaming | 1230029 | t | 412880112 | 412880112 orders_streaming | 1230032 | t | 412880112 | 412880112 lineitem_streaming | 1230044 | t | 412880113 | 2147483646 orders_streaming | 1230046 | t | 412880113 | 2147483646 lineitem_streaming | 1230045 | t | 2147483647 | 2147483647 orders_streaming | 1230047 | t | 2147483647 | 2147483647 (24 rows) \c - postgres - :master_port CALL pg_catalog.citus_cleanup_orphaned_resources(); -- test failure scenarios with triggers on workers \c - postgres - :worker_1_port SET search_path to "Tenant Isolation"; SET citus.enable_metadata_sync TO OFF; CREATE OR REPLACE FUNCTION abort_any_command() RETURNS event_trigger LANGUAGE plpgsql AS $$ BEGIN RAISE EXCEPTION 'command % is disabled', tg_tag; END; $$; RESET citus.enable_metadata_sync; CREATE EVENT TRIGGER abort_ddl ON ddl_command_end EXECUTE PROCEDURE abort_any_command(); SET citus.override_table_visibility TO false; \d List of relations Schema | Name | Type | Owner --------------------------------------------------------------------- Tenant Isolation | lineitem_streaming | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230011 | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230012 | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230035 | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230036 | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230040 | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230041 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230014 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230015 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230038 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230039 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230042 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230043 | table | mx_isolation_role_ent Tenant Isolation | text_column | table | mx_isolation_role_ent Tenant Isolation | text_column_1230052 | table | mx_isolation_role_ent Tenant Isolation | text_column_1230053 | table | mx_isolation_role_ent Tenant Isolation | text_column_1230054 | table | mx_isolation_role_ent (18 rows) \c - mx_isolation_role_ent - :master_port SET search_path to "Tenant Isolation"; \set VERBOSITY terse SELECT isolate_tenant_to_new_shard('orders_streaming', 104, 'CASCADE', shard_transfer_mode => 'force_logical'); WARNING: command DROP TABLE is disabled WARNING: Failed to cleanup 1 shards out of 1 ERROR: command CREATE TABLE is disabled \set VERBOSITY default \c - postgres - :worker_1_port SET search_path to "Tenant Isolation"; SET citus.override_table_visibility TO false; \d List of relations Schema | Name | Type | Owner --------------------------------------------------------------------- Tenant Isolation | lineitem_streaming | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230011 | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230012 | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230035 | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230036 | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230040 | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230041 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230014 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230015 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230038 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230039 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230042 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230043 | table | mx_isolation_role_ent Tenant Isolation | text_column | table | mx_isolation_role_ent Tenant Isolation | text_column_1230052 | table | mx_isolation_role_ent Tenant Isolation | text_column_1230053 | table | mx_isolation_role_ent Tenant Isolation | text_column_1230054 | table | mx_isolation_role_ent (18 rows) DROP EVENT TRIGGER abort_ddl; -- create a trigger for drops SET citus.enable_metadata_sync TO OFF; CREATE OR REPLACE FUNCTION abort_drop_command() RETURNS event_trigger LANGUAGE plpgsql AS $$ BEGIN RAISE EXCEPTION 'command % is disabled', tg_tag; END; $$; RESET citus.enable_metadata_sync; CREATE EVENT TRIGGER abort_drop ON sql_drop EXECUTE PROCEDURE abort_drop_command(); \c - mx_isolation_role_ent - :master_port SET search_path to "Tenant Isolation"; \set VERBOSITY terse SELECT isolate_tenant_to_new_shard('orders_streaming', 104, 'CASCADE', shard_transfer_mode => 'force_logical'); ERROR: command DROP SUBSCRIPTION is disabled \set VERBOSITY default -- check if metadata is changed SELECT * FROM pg_dist_shard WHERE logicalrelid = 'lineitem_streaming'::regclass OR logicalrelid = 'orders_streaming'::regclass ORDER BY shardminvalue::BIGINT, logicalrelid; logicalrelid | shardid | shardstorage | shardminvalue | shardmaxvalue --------------------------------------------------------------------- lineitem_streaming | 1230040 | t | -2147483648 | -2147483648 orders_streaming | 1230042 | t | -2147483648 | -2147483648 lineitem_streaming | 1230041 | t | -2147483647 | -136164586 orders_streaming | 1230043 | t | -2147483647 | -136164586 lineitem_streaming | 1230035 | t | -136164585 | -136164585 orders_streaming | 1230038 | t | -136164585 | -136164585 lineitem_streaming | 1230036 | t | -136164584 | -85071815 orders_streaming | 1230039 | t | -136164584 | -85071815 lineitem_streaming | 1230011 | t | -85071814 | -85071814 orders_streaming | 1230014 | t | -85071814 | -85071814 lineitem_streaming | 1230012 | t | -85071813 | -1 orders_streaming | 1230015 | t | -85071813 | -1 lineitem_streaming | 1230004 | t | 0 | 108199380 orders_streaming | 1230007 | t | 0 | 108199380 lineitem_streaming | 1230005 | t | 108199381 | 108199381 orders_streaming | 1230008 | t | 108199381 | 108199381 lineitem_streaming | 1230028 | t | 108199382 | 412880111 orders_streaming | 1230031 | t | 108199382 | 412880111 lineitem_streaming | 1230029 | t | 412880112 | 412880112 orders_streaming | 1230032 | t | 412880112 | 412880112 lineitem_streaming | 1230044 | t | 412880113 | 2147483646 orders_streaming | 1230046 | t | 412880113 | 2147483646 lineitem_streaming | 1230045 | t | 2147483647 | 2147483647 orders_streaming | 1230047 | t | 2147483647 | 2147483647 (24 rows) \c - - - :worker_1_port SET search_path to "Tenant Isolation"; -- however, new tables are already created SET citus.override_table_visibility TO false; \d List of relations Schema | Name | Type | Owner --------------------------------------------------------------------- Tenant Isolation | lineitem_streaming | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230011 | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230012 | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230035 | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230036 | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230040 | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230041 | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230061 | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230062 | table | mx_isolation_role_ent Tenant Isolation | lineitem_streaming_1230063 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230014 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230015 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230038 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230039 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230042 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230043 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230064 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230065 | table | mx_isolation_role_ent Tenant Isolation | orders_streaming_1230066 | table | mx_isolation_role_ent Tenant Isolation | text_column | table | mx_isolation_role_ent Tenant Isolation | text_column_1230052 | table | mx_isolation_role_ent Tenant Isolation | text_column_1230053 | table | mx_isolation_role_ent Tenant Isolation | text_column_1230054 | table | mx_isolation_role_ent (24 rows) \c - postgres - :worker_1_port DROP EVENT TRIGGER abort_drop; \c - mx_isolation_role_ent - :master_port SET search_path to "Tenant Isolation"; -- tests for cluster health SELECT count(*) FROM lineitem_streaming; count --------------------------------------------------------------------- 22 (1 row) SELECT count(*) FROM orders_streaming; count --------------------------------------------------------------------- 7 (1 row) SELECT l_orderkey, sum(l_extendedprice * (1 - l_discount)) as revenue, o_orderdate FROM orders_streaming, lineitem_streaming WHERE l_orderkey = o_orderkey GROUP BY l_orderkey, o_orderdate ORDER BY revenue DESC, o_orderdate; l_orderkey | revenue | o_orderdate --------------------------------------------------------------------- 100 | 181042.2683 | 02-28-1998 102 | 159639.9677 | 05-09-1997 101 | 124074.5328 | 03-17-1996 103 | 119741.5469 | 06-20-1996 99 | 109604.3256 | 03-13-1994 -1995148554 | 16890.6816 | 05-08-1995 -1686493264 | 1988.7134 | 09-05-1997 (7 rows) SELECT count(*) FROM lineitem_streaming WHERE l_orderkey = 99; count --------------------------------------------------------------------- 4 (1 row) SELECT count(*) FROM lineitem_streaming WHERE l_orderkey = 100; count --------------------------------------------------------------------- 5 (1 row) SELECT count(*) FROM lineitem_streaming WHERE l_orderkey = 101; count --------------------------------------------------------------------- 3 (1 row) SELECT count(*) FROM lineitem_streaming WHERE l_orderkey = 102; count --------------------------------------------------------------------- 4 (1 row) SELECT count(*) FROM lineitem_streaming WHERE l_orderkey = 103; count --------------------------------------------------------------------- 4 (1 row) SELECT count(*) FROM orders_streaming WHERE o_orderkey = 99; count --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM orders_streaming WHERE o_orderkey = 100; count --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM orders_streaming WHERE o_orderkey = 101; count --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM orders_streaming WHERE o_orderkey = 102; count --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM orders_streaming WHERE o_orderkey = 103; count --------------------------------------------------------------------- 1 (1 row) -- test composite types with tenant isolation set search_path to default; \c - postgres - :worker_1_port SET search_path to "Tenant Isolation", public, pg_catalog; -- ... create a test HASH function. Though it is a poor hash function, -- it is acceptable for our tests SET citus.enable_metadata_sync TO OFF; CREATE FUNCTION test_composite_type_hash(test_composite_type) RETURNS int AS 'SELECT hashtext( ($1.i + $1.i2)::text);' LANGUAGE SQL IMMUTABLE RETURNS NULL ON NULL INPUT; RESET citus.enable_metadata_sync; CREATE OPERATOR CLASS cats_op_fam_class DEFAULT FOR TYPE test_composite_type USING HASH AS OPERATOR 1 = (test_composite_type, test_composite_type), FUNCTION 1 test_composite_type_hash(test_composite_type); \c - - - :worker_2_port SET search_path to "Tenant Isolation", public, pg_catalog; -- ... create a test HASH function. Though it is a poor hash function, -- it is acceptable for our tests SET citus.enable_metadata_sync TO OFF; CREATE FUNCTION test_composite_type_hash(test_composite_type) RETURNS int AS 'SELECT hashtext( ($1.i + $1.i2)::text);' LANGUAGE SQL IMMUTABLE RETURNS NULL ON NULL INPUT; RESET citus.enable_metadata_sync; CREATE OPERATOR CLASS cats_op_fam_class DEFAULT FOR TYPE test_composite_type USING HASH AS OPERATOR 1 = (test_composite_type, test_composite_type), FUNCTION 1 test_composite_type_hash(test_composite_type); \c - mx_isolation_role_ent - :master_port SET search_path to "Tenant Isolation", public, pg_catalog; CREATE TABLE composite_table ( composite_key test_composite_type); SELECT create_distributed_table('composite_table', 'composite_key'); create_distributed_table --------------------------------------------------------------------- (1 row) INSERT INTO composite_table VALUES ('(1, 2)'::test_composite_type); INSERT INTO composite_table VALUES ('(1, 3)'::test_composite_type); INSERT INTO composite_table VALUES ('(1, 4)'::test_composite_type); SELECT isolate_tenant_to_new_shard('composite_table', '(1, 3)', shard_transfer_mode => 'force_logical'); ERROR: cannot isolate tenants when using shard replication SELECT count(*) FROM composite_table WHERE composite_key = '(1, 2)'::test_composite_type; count --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM composite_table WHERE composite_key = '(1, 3)'::test_composite_type; count --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM composite_table WHERE composite_key = '(1, 4)'::test_composite_type; count --------------------------------------------------------------------- 1 (1 row) DROP TABLE composite_table; -- create foreign keys from a reference and distributed table -- to another distributed table SET search_path to "Tenant Isolation", public, pg_catalog; SET citus.shard_replication_factor TO 1; SET citus.shard_count to 8; CREATE TABLE test_reference_table_fkey(id int PRIMARY KEY); SELECT create_reference_table('test_reference_table_fkey'); create_reference_table --------------------------------------------------------------------- (1 row) CREATE TABLE test_colocated_table_1(id int PRIMARY KEY, value_1 int, FOREIGN KEY(id) REFERENCES test_colocated_table_1(id)); SELECT create_distributed_table('test_colocated_table_1', 'id', colocate_with => 'NONE'); create_distributed_table --------------------------------------------------------------------- (1 row) CREATE TABLE test_colocated_table_2(id int PRIMARY KEY, value_1 int, FOREIGN KEY(value_1) REFERENCES test_reference_table_fkey(id), FOREIGN KEY(id) REFERENCES test_colocated_table_1(id)); SELECT create_distributed_table('test_colocated_table_2', 'id', colocate_with => 'test_colocated_table_1'); create_distributed_table --------------------------------------------------------------------- (1 row) CREATE TABLE test_colocated_table_3(id int PRIMARY KEY, value_1 int, FOREIGN KEY(value_1) REFERENCES test_reference_table_fkey(id), FOREIGN KEY(id) REFERENCES test_colocated_table_1(id), FOREIGN KEY(id) REFERENCES test_colocated_table_2(id)); SELECT create_distributed_table('test_colocated_table_3', 'id', colocate_with => 'test_colocated_table_1'); create_distributed_table --------------------------------------------------------------------- (1 row) CREATE TABLE test_colocated_table_no_rep_identity(id int, value_1 int, FOREIGN KEY(value_1) REFERENCES test_reference_table_fkey(id), FOREIGN KEY(id) REFERENCES test_colocated_table_1(id), FOREIGN KEY(id) REFERENCES test_colocated_table_2(id)); SELECT create_distributed_table('test_colocated_table_no_rep_identity', 'id', colocate_with => 'test_colocated_table_1'); create_distributed_table --------------------------------------------------------------------- (1 row) INSERT INTO test_reference_table_fkey SELECT i FROM generate_series (0, 100) i; INSERT INTO test_colocated_table_1 SELECT i, i FROM generate_series (0, 100) i; INSERT INTO test_colocated_table_2 SELECT i, i FROM generate_series (0, 100) i; INSERT INTO test_colocated_table_3 SELECT i, i FROM generate_series (0, 100) i; INSERT INTO test_colocated_table_no_rep_identity SELECT i, i FROM generate_series (0, 100) i; -- show that we donot support tenant isolation if the table has a colocated table with no replica identity and shard_transfer_mode=auto SELECT isolate_tenant_to_new_shard('test_colocated_table_2', 1, 'CASCADE', shard_transfer_mode => 'auto'); ERROR: cannot use logical replication to transfer shards of the relation test_colocated_table_no_rep_identity since it doesn't have a REPLICA IDENTITY or PRIMARY KEY DETAIL: UPDATE and DELETE commands on the shard will error out during logical replication unless there is a REPLICA IDENTITY or PRIMARY KEY. HINT: If you wish to continue without a replica identity set the shard_transfer_mode to 'force_logical' or 'block_writes'. -- show that we can isolate it after removing the colocated table with no replica identity DROP TABLE test_colocated_table_no_rep_identity; SELECT isolate_tenant_to_new_shard('test_colocated_table_2', 1, 'CASCADE', shard_transfer_mode => 'auto'); isolate_tenant_to_new_shard --------------------------------------------------------------------- 1230108 (1 row) SELECT count(*) FROM test_colocated_table_2; count --------------------------------------------------------------------- 101 (1 row) \c - postgres - :master_port CALL pg_catalog.citus_cleanup_orphaned_resources(); NOTICE: cleaned up 10 orphaned resources \c - postgres - :worker_1_port -- show the foreign keys of the main table & its colocated shard on other tables SELECT tbl.relname, fk."Constraint", fk."Definition" FROM pg_catalog.pg_class tbl JOIN public.table_fkeys fk on tbl.oid = fk.relid WHERE tbl.relname like 'test_colocated_table_%' ORDER BY 1, 2; relname | Constraint | Definition --------------------------------------------------------------------- test_colocated_table_1 | test_colocated_table_1_id_fkey | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1(id) test_colocated_table_1_1230074 | test_colocated_table_1_id_fkey_1230074 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230074(id) test_colocated_table_1_1230076 | test_colocated_table_1_id_fkey_1230076 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230076(id) test_colocated_table_1_1230078 | test_colocated_table_1_id_fkey_1230078 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230078(id) test_colocated_table_1_1230104 | test_colocated_table_1_id_fkey_1230104 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230104(id) test_colocated_table_1_1230105 | test_colocated_table_1_id_fkey_1230105 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230105(id) test_colocated_table_1_1230106 | test_colocated_table_1_id_fkey_1230106 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230106(id) test_colocated_table_2 | test_colocated_table_2_id_fkey | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1(id) test_colocated_table_2 | test_colocated_table_2_value_1_fkey | FOREIGN KEY (value_1) REFERENCES "Tenant Isolation".test_reference_table_fkey(id) test_colocated_table_2_1230082 | test_colocated_table_2_id_fkey_1230082 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230074(id) test_colocated_table_2_1230082 | test_colocated_table_2_value_1_fkey_1230082 | FOREIGN KEY (value_1) REFERENCES "Tenant Isolation".test_reference_table_fkey_1230071(id) test_colocated_table_2_1230084 | test_colocated_table_2_id_fkey_1230084 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230076(id) test_colocated_table_2_1230084 | test_colocated_table_2_value_1_fkey_1230084 | FOREIGN KEY (value_1) REFERENCES "Tenant Isolation".test_reference_table_fkey_1230071(id) test_colocated_table_2_1230086 | test_colocated_table_2_id_fkey_1230086 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230078(id) test_colocated_table_2_1230086 | test_colocated_table_2_value_1_fkey_1230086 | FOREIGN KEY (value_1) REFERENCES "Tenant Isolation".test_reference_table_fkey_1230071(id) test_colocated_table_2_1230107 | test_colocated_table_2_id_fkey_1230107 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230104(id) test_colocated_table_2_1230107 | test_colocated_table_2_value_1_fkey_1230107 | FOREIGN KEY (value_1) REFERENCES "Tenant Isolation".test_reference_table_fkey_1230071(id) test_colocated_table_2_1230108 | test_colocated_table_2_id_fkey_1230108 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230105(id) test_colocated_table_2_1230108 | test_colocated_table_2_value_1_fkey_1230108 | FOREIGN KEY (value_1) REFERENCES "Tenant Isolation".test_reference_table_fkey_1230071(id) test_colocated_table_2_1230109 | test_colocated_table_2_id_fkey_1230109 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230106(id) test_colocated_table_2_1230109 | test_colocated_table_2_value_1_fkey_1230109 | FOREIGN KEY (value_1) REFERENCES "Tenant Isolation".test_reference_table_fkey_1230071(id) test_colocated_table_3 | test_colocated_table_3_id_fkey | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1(id) test_colocated_table_3 | test_colocated_table_3_id_fkey1 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_2(id) test_colocated_table_3 | test_colocated_table_3_value_1_fkey | FOREIGN KEY (value_1) REFERENCES "Tenant Isolation".test_reference_table_fkey(id) test_colocated_table_3_1230090 | test_colocated_table_3_id_fkey1_1230090 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_2_1230082(id) test_colocated_table_3_1230090 | test_colocated_table_3_id_fkey_1230090 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230074(id) test_colocated_table_3_1230090 | test_colocated_table_3_value_1_fkey_1230090 | FOREIGN KEY (value_1) REFERENCES "Tenant Isolation".test_reference_table_fkey_1230071(id) test_colocated_table_3_1230092 | test_colocated_table_3_id_fkey1_1230092 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_2_1230084(id) test_colocated_table_3_1230092 | test_colocated_table_3_id_fkey_1230092 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230076(id) test_colocated_table_3_1230092 | test_colocated_table_3_value_1_fkey_1230092 | FOREIGN KEY (value_1) REFERENCES "Tenant Isolation".test_reference_table_fkey_1230071(id) test_colocated_table_3_1230094 | test_colocated_table_3_id_fkey1_1230094 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_2_1230086(id) test_colocated_table_3_1230094 | test_colocated_table_3_id_fkey_1230094 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230078(id) test_colocated_table_3_1230094 | test_colocated_table_3_value_1_fkey_1230094 | FOREIGN KEY (value_1) REFERENCES "Tenant Isolation".test_reference_table_fkey_1230071(id) test_colocated_table_3_1230110 | test_colocated_table_3_id_fkey1_1230110 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_2_1230107(id) test_colocated_table_3_1230110 | test_colocated_table_3_id_fkey_1230110 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230104(id) test_colocated_table_3_1230110 | test_colocated_table_3_value_1_fkey_1230110 | FOREIGN KEY (value_1) REFERENCES "Tenant Isolation".test_reference_table_fkey_1230071(id) test_colocated_table_3_1230111 | test_colocated_table_3_id_fkey1_1230111 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_2_1230108(id) test_colocated_table_3_1230111 | test_colocated_table_3_id_fkey_1230111 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230105(id) test_colocated_table_3_1230111 | test_colocated_table_3_value_1_fkey_1230111 | FOREIGN KEY (value_1) REFERENCES "Tenant Isolation".test_reference_table_fkey_1230071(id) test_colocated_table_3_1230112 | test_colocated_table_3_id_fkey1_1230112 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_2_1230109(id) test_colocated_table_3_1230112 | test_colocated_table_3_id_fkey_1230112 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230106(id) test_colocated_table_3_1230112 | test_colocated_table_3_value_1_fkey_1230112 | FOREIGN KEY (value_1) REFERENCES "Tenant Isolation".test_reference_table_fkey_1230071(id) (42 rows) \c - mx_isolation_role_ent - :master_port SET search_path to "Tenant Isolation"; -- -- Make sure that isolate_tenant_to_new_shard() replicats reference tables -- when replicate_reference_tables_on_activate is off. -- CREATE TABLE ref_table(a int); SELECT create_reference_table('ref_table'); create_reference_table --------------------------------------------------------------------- (1 row) \c - postgres - :master_port SET search_path to "Tenant Isolation"; -- partitioning tests -- create partitioned table CREATE TABLE partitioning_test(id int, time date) PARTITION BY RANGE (time); -- create a regular partition CREATE TABLE partitioning_test_2009 PARTITION OF partitioning_test FOR VALUES FROM ('2009-01-01') TO ('2010-01-01'); -- create a columnar partition CREATE TABLE partitioning_test_2010 PARTITION OF partitioning_test FOR VALUES FROM ('2010-01-01') TO ('2011-01-01') USING columnar; -- load some data and distribute tables INSERT INTO partitioning_test VALUES (1, '2009-06-06'); INSERT INTO partitioning_test VALUES (2, '2010-07-07'); INSERT INTO partitioning_test_2009 VALUES (3, '2009-09-09'); INSERT INTO partitioning_test_2010 VALUES (4, '2010-03-03'); -- distribute partitioned table SET citus.shard_replication_factor TO 1; SELECT create_distributed_table('partitioning_test', 'id'); NOTICE: Copying data from local table... NOTICE: copying the data has completed DETAIL: The local data in the table is no longer visible, but is still on disk. HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$"Tenant Isolation".partitioning_test_2009$$) NOTICE: Copying data from local table... NOTICE: copying the data has completed DETAIL: The local data in the table is no longer visible, but is still on disk. HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$"Tenant Isolation".partitioning_test_2010$$) create_distributed_table --------------------------------------------------------------------- (1 row) SELECT count(*) FROM pg_dist_shard WHERE logicalrelid = 'partitioning_test'::regclass; count --------------------------------------------------------------------- 4 (1 row) SELECT count(*) FROM partitioning_test; count --------------------------------------------------------------------- 4 (1 row) -- isolate a value into its own shard SELECT 1 FROM isolate_tenant_to_new_shard('partitioning_test', 2, 'CASCADE', shard_transfer_mode => 'force_logical'); ?column? --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM pg_dist_shard WHERE logicalrelid = 'partitioning_test'::regclass; count --------------------------------------------------------------------- 6 (1 row) SELECT count(*) FROM partitioning_test; count --------------------------------------------------------------------- 4 (1 row) SET citus.replicate_reference_tables_on_activate TO off; SET client_min_messages TO WARNING; SELECT 1 FROM master_add_node('localhost', :master_port, groupId=>0); ?column? --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM pg_dist_shard NATURAL JOIN pg_dist_shard_placement WHERE logicalrelid = 'ref_table'::regclass; count --------------------------------------------------------------------- 2 (1 row) \c - mx_isolation_role_ent - :master_port SET search_path to "Tenant Isolation"; SELECT 1 FROM isolate_tenant_to_new_shard('test_colocated_table_2', 2, 'CASCADE', shard_transfer_mode => 'force_logical'); ?column? --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM pg_dist_shard NATURAL JOIN pg_dist_shard_placement WHERE logicalrelid = 'ref_table'::regclass; count --------------------------------------------------------------------- 3 (1 row) \c - postgres - :master_port SELECT 1 FROM master_remove_node('localhost', :master_port); ?column? --------------------------------------------------------------------- 1 (1 row) SET client_min_messages TO WARNING; DROP SCHEMA "Tenant Isolation" CASCADE; REVOKE ALL ON SCHEMA public FROM mx_isolation_role_ent; DROP ROLE mx_isolation_role_ent; -- stop & resync and stop syncing metadata SELECT stop_metadata_sync_to_node('localhost', :worker_1_port); stop_metadata_sync_to_node --------------------------------------------------------------------- (1 row) SELECT start_metadata_sync_to_node('localhost', :worker_1_port); start_metadata_sync_to_node --------------------------------------------------------------------- (1 row) SELECT stop_metadata_sync_to_node('localhost', :worker_1_port); stop_metadata_sync_to_node --------------------------------------------------------------------- (1 row) -- restart metadata sync for rest of the tests SELECT start_metadata_sync_to_node('localhost', :worker_1_port); start_metadata_sync_to_node --------------------------------------------------------------------- (1 row) -- make sure there are no tables with non-zero colocationid SELECT count(*) FROM pg_catalog.pg_dist_partition WHERE colocationid > 0; count --------------------------------------------------------------------- 0 (1 row) TRUNCATE TABLE pg_catalog.pg_dist_colocation; ALTER SEQUENCE pg_catalog.pg_dist_colocationid_seq RESTART 100; ALTER SEQUENCE pg_catalog.pg_dist_placement_placementid_seq RESTART :last_placement_id;