mirror of https://github.com/citusdata/citus.git
multi_tenant_isolation edit
parent
3b231b70d8
commit
5aedb82268
|
@ -497,20 +497,26 @@ SET citus.override_table_visibility TO false;
|
||||||
Schema | Name | Type | Owner
|
Schema | Name | Type | Owner
|
||||||
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
||||||
Tenant Isolation | lineitem_streaming | table | mx_isolation_role_ent
|
Tenant Isolation | lineitem_streaming | table | mx_isolation_role_ent
|
||||||
|
Tenant Isolation | lineitem_streaming_1230000 | table | mx_isolation_role_ent
|
||||||
|
Tenant Isolation | lineitem_streaming_1230010 | table | mx_isolation_role_ent
|
||||||
Tenant Isolation | lineitem_streaming_1230011 | 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_1230012 | table | mx_isolation_role_ent
|
||||||
|
Tenant Isolation | lineitem_streaming_1230034 | table | mx_isolation_role_ent
|
||||||
Tenant Isolation | lineitem_streaming_1230035 | 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_1230036 | table | mx_isolation_role_ent
|
||||||
Tenant Isolation | lineitem_streaming_1230040 | 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_1230041 | table | mx_isolation_role_ent
|
||||||
Tenant Isolation | orders_streaming | table | mx_isolation_role_ent
|
Tenant Isolation | orders_streaming | table | mx_isolation_role_ent
|
||||||
|
Tenant Isolation | orders_streaming_1230002 | table | mx_isolation_role_ent
|
||||||
|
Tenant Isolation | orders_streaming_1230013 | table | mx_isolation_role_ent
|
||||||
Tenant Isolation | orders_streaming_1230014 | 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_1230015 | table | mx_isolation_role_ent
|
||||||
|
Tenant Isolation | orders_streaming_1230037 | table | mx_isolation_role_ent
|
||||||
Tenant Isolation | orders_streaming_1230038 | 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_1230039 | table | mx_isolation_role_ent
|
||||||
Tenant Isolation | orders_streaming_1230042 | 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_1230043 | table | mx_isolation_role_ent
|
||||||
(14 rows)
|
(20 rows)
|
||||||
|
|
||||||
\c - postgres - :worker_1_port
|
\c - postgres - :worker_1_port
|
||||||
SET search_path to "Tenant Isolation";
|
SET search_path to "Tenant Isolation";
|
||||||
|
@ -734,25 +740,33 @@ SET citus.override_table_visibility TO false;
|
||||||
Schema | Name | Type | Owner
|
Schema | Name | Type | Owner
|
||||||
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
||||||
Tenant Isolation | lineitem_streaming | table | mx_isolation_role_ent
|
Tenant Isolation | lineitem_streaming | table | mx_isolation_role_ent
|
||||||
|
Tenant Isolation | lineitem_streaming_1230000 | table | mx_isolation_role_ent
|
||||||
|
Tenant Isolation | lineitem_streaming_1230010 | table | mx_isolation_role_ent
|
||||||
Tenant Isolation | lineitem_streaming_1230011 | 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_1230012 | table | mx_isolation_role_ent
|
||||||
|
Tenant Isolation | lineitem_streaming_1230034 | table | mx_isolation_role_ent
|
||||||
Tenant Isolation | lineitem_streaming_1230035 | 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_1230036 | table | mx_isolation_role_ent
|
||||||
Tenant Isolation | lineitem_streaming_1230040 | 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_1230041 | table | mx_isolation_role_ent
|
||||||
Tenant Isolation | orders_streaming | table | mx_isolation_role_ent
|
Tenant Isolation | orders_streaming | table | mx_isolation_role_ent
|
||||||
|
Tenant Isolation | orders_streaming_1230002 | table | mx_isolation_role_ent
|
||||||
|
Tenant Isolation | orders_streaming_1230013 | table | mx_isolation_role_ent
|
||||||
Tenant Isolation | orders_streaming_1230014 | 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_1230015 | table | mx_isolation_role_ent
|
||||||
|
Tenant Isolation | orders_streaming_1230037 | table | mx_isolation_role_ent
|
||||||
Tenant Isolation | orders_streaming_1230038 | 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_1230039 | table | mx_isolation_role_ent
|
||||||
Tenant Isolation | orders_streaming_1230042 | 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_1230043 | table | mx_isolation_role_ent
|
||||||
(14 rows)
|
(20 rows)
|
||||||
|
|
||||||
\c - mx_isolation_role_ent - :master_port
|
\c - mx_isolation_role_ent - :master_port
|
||||||
SET search_path to "Tenant Isolation";
|
SET search_path to "Tenant Isolation";
|
||||||
\set VERBOSITY terse
|
\set VERBOSITY terse
|
||||||
SELECT isolate_tenant_to_new_shard('orders_streaming', 104, 'CASCADE', shard_transfer_mode => 'block_writes');
|
SELECT isolate_tenant_to_new_shard('orders_streaming', 104, 'CASCADE', shard_transfer_mode => 'block_writes');
|
||||||
|
WARNING: command DROP TABLE is disabled
|
||||||
|
WARNING: Failed to drop 1 cleanup shards out of 1
|
||||||
ERROR: command CREATE TABLE is disabled
|
ERROR: command CREATE TABLE is disabled
|
||||||
\set VERBOSITY default
|
\set VERBOSITY default
|
||||||
\c - postgres - :worker_1_port
|
\c - postgres - :worker_1_port
|
||||||
|
@ -763,20 +777,26 @@ SET citus.override_table_visibility TO false;
|
||||||
Schema | Name | Type | Owner
|
Schema | Name | Type | Owner
|
||||||
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
||||||
Tenant Isolation | lineitem_streaming | table | mx_isolation_role_ent
|
Tenant Isolation | lineitem_streaming | table | mx_isolation_role_ent
|
||||||
|
Tenant Isolation | lineitem_streaming_1230000 | table | mx_isolation_role_ent
|
||||||
|
Tenant Isolation | lineitem_streaming_1230010 | table | mx_isolation_role_ent
|
||||||
Tenant Isolation | lineitem_streaming_1230011 | 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_1230012 | table | mx_isolation_role_ent
|
||||||
|
Tenant Isolation | lineitem_streaming_1230034 | table | mx_isolation_role_ent
|
||||||
Tenant Isolation | lineitem_streaming_1230035 | 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_1230036 | table | mx_isolation_role_ent
|
||||||
Tenant Isolation | lineitem_streaming_1230040 | 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_1230041 | table | mx_isolation_role_ent
|
||||||
Tenant Isolation | orders_streaming | table | mx_isolation_role_ent
|
Tenant Isolation | orders_streaming | table | mx_isolation_role_ent
|
||||||
|
Tenant Isolation | orders_streaming_1230002 | table | mx_isolation_role_ent
|
||||||
|
Tenant Isolation | orders_streaming_1230013 | table | mx_isolation_role_ent
|
||||||
Tenant Isolation | orders_streaming_1230014 | 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_1230015 | table | mx_isolation_role_ent
|
||||||
|
Tenant Isolation | orders_streaming_1230037 | table | mx_isolation_role_ent
|
||||||
Tenant Isolation | orders_streaming_1230038 | 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_1230039 | table | mx_isolation_role_ent
|
||||||
Tenant Isolation | orders_streaming_1230042 | 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_1230043 | table | mx_isolation_role_ent
|
||||||
(14 rows)
|
(20 rows)
|
||||||
|
|
||||||
DROP EVENT TRIGGER abort_ddl;
|
DROP EVENT TRIGGER abort_ddl;
|
||||||
-- create a trigger for drops
|
-- create a trigger for drops
|
||||||
|
@ -792,497 +812,5 @@ $$;
|
||||||
RESET citus.enable_metadata_sync;
|
RESET citus.enable_metadata_sync;
|
||||||
CREATE EVENT TRIGGER abort_drop ON sql_drop
|
CREATE EVENT TRIGGER abort_drop ON sql_drop
|
||||||
EXECUTE PROCEDURE abort_drop_command();
|
EXECUTE PROCEDURE abort_drop_command();
|
||||||
\c - mx_isolation_role_ent - :master_port
|
\c :master_port
|
||||||
SET search_path to "Tenant Isolation";
|
\connect: FATAL: database "57636" does not exist
|
||||||
\set VERBOSITY terse
|
|
||||||
SELECT isolate_tenant_to_new_shard('orders_streaming', 104, 'CASCADE', shard_transfer_mode => 'block_writes');
|
|
||||||
WARNING: command DROP TABLE is disabled
|
|
||||||
WARNING: command DROP TABLE is disabled
|
|
||||||
WARNING: command DROP TABLE is disabled
|
|
||||||
WARNING: command DROP TABLE is disabled
|
|
||||||
WARNING: command DROP TABLE is disabled
|
|
||||||
WARNING: command DROP TABLE is disabled
|
|
||||||
ERROR: command DROP TABLE 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_1230056 | table | mx_isolation_role_ent
|
|
||||||
Tenant Isolation | lineitem_streaming_1230057 | table | mx_isolation_role_ent
|
|
||||||
Tenant Isolation | lineitem_streaming_1230058 | 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_1230059 | table | mx_isolation_role_ent
|
|
||||||
Tenant Isolation | orders_streaming_1230060 | table | mx_isolation_role_ent
|
|
||||||
Tenant Isolation | orders_streaming_1230061 | table | mx_isolation_role_ent
|
|
||||||
(20 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 => 'block_writes');
|
|
||||||
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)
|
|
||||||
|
|
||||||
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;
|
|
||||||
SELECT isolate_tenant_to_new_shard('test_colocated_table_2', 1, 'CASCADE', shard_transfer_mode => 'block_writes');
|
|
||||||
isolate_tenant_to_new_shard
|
|
||||||
---------------------------------------------------------------------
|
|
||||||
1230095
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
SELECT count(*) FROM test_colocated_table_2;
|
|
||||||
count
|
|
||||||
---------------------------------------------------------------------
|
|
||||||
101
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
\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_1230069 | test_colocated_table_1_id_fkey_1230069 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230069(id)
|
|
||||||
test_colocated_table_1_1230071 | test_colocated_table_1_id_fkey_1230071 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230071(id)
|
|
||||||
test_colocated_table_1_1230073 | test_colocated_table_1_id_fkey_1230073 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230073(id)
|
|
||||||
test_colocated_table_1_1230091 | test_colocated_table_1_id_fkey_1230091 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230091(id)
|
|
||||||
test_colocated_table_1_1230092 | test_colocated_table_1_id_fkey_1230092 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230092(id)
|
|
||||||
test_colocated_table_1_1230093 | test_colocated_table_1_id_fkey_1230093 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230093(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_1230077 | test_colocated_table_2_id_fkey_1230077 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230069(id)
|
|
||||||
test_colocated_table_2_1230077 | test_colocated_table_2_value_1_fkey_1230077 | FOREIGN KEY (value_1) REFERENCES "Tenant Isolation".test_reference_table_fkey_1230066(id)
|
|
||||||
test_colocated_table_2_1230079 | test_colocated_table_2_id_fkey_1230079 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230071(id)
|
|
||||||
test_colocated_table_2_1230079 | test_colocated_table_2_value_1_fkey_1230079 | FOREIGN KEY (value_1) REFERENCES "Tenant Isolation".test_reference_table_fkey_1230066(id)
|
|
||||||
test_colocated_table_2_1230081 | test_colocated_table_2_id_fkey_1230081 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230073(id)
|
|
||||||
test_colocated_table_2_1230081 | test_colocated_table_2_value_1_fkey_1230081 | FOREIGN KEY (value_1) REFERENCES "Tenant Isolation".test_reference_table_fkey_1230066(id)
|
|
||||||
test_colocated_table_2_1230094 | test_colocated_table_2_id_fkey_1230094 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230091(id)
|
|
||||||
test_colocated_table_2_1230094 | test_colocated_table_2_value_1_fkey_1230094 | FOREIGN KEY (value_1) REFERENCES "Tenant Isolation".test_reference_table_fkey_1230066(id)
|
|
||||||
test_colocated_table_2_1230095 | test_colocated_table_2_id_fkey_1230095 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230092(id)
|
|
||||||
test_colocated_table_2_1230095 | test_colocated_table_2_value_1_fkey_1230095 | FOREIGN KEY (value_1) REFERENCES "Tenant Isolation".test_reference_table_fkey_1230066(id)
|
|
||||||
test_colocated_table_2_1230096 | test_colocated_table_2_id_fkey_1230096 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230093(id)
|
|
||||||
test_colocated_table_2_1230096 | test_colocated_table_2_value_1_fkey_1230096 | FOREIGN KEY (value_1) REFERENCES "Tenant Isolation".test_reference_table_fkey_1230066(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_1230085 | test_colocated_table_3_id_fkey1_1230085 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_2_1230077(id)
|
|
||||||
test_colocated_table_3_1230085 | test_colocated_table_3_id_fkey_1230085 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230069(id)
|
|
||||||
test_colocated_table_3_1230085 | test_colocated_table_3_value_1_fkey_1230085 | FOREIGN KEY (value_1) REFERENCES "Tenant Isolation".test_reference_table_fkey_1230066(id)
|
|
||||||
test_colocated_table_3_1230087 | test_colocated_table_3_id_fkey1_1230087 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_2_1230079(id)
|
|
||||||
test_colocated_table_3_1230087 | test_colocated_table_3_id_fkey_1230087 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230071(id)
|
|
||||||
test_colocated_table_3_1230087 | test_colocated_table_3_value_1_fkey_1230087 | FOREIGN KEY (value_1) REFERENCES "Tenant Isolation".test_reference_table_fkey_1230066(id)
|
|
||||||
test_colocated_table_3_1230089 | test_colocated_table_3_id_fkey1_1230089 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_2_1230081(id)
|
|
||||||
test_colocated_table_3_1230089 | test_colocated_table_3_id_fkey_1230089 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230073(id)
|
|
||||||
test_colocated_table_3_1230089 | test_colocated_table_3_value_1_fkey_1230089 | FOREIGN KEY (value_1) REFERENCES "Tenant Isolation".test_reference_table_fkey_1230066(id)
|
|
||||||
test_colocated_table_3_1230097 | test_colocated_table_3_id_fkey1_1230097 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_2_1230094(id)
|
|
||||||
test_colocated_table_3_1230097 | test_colocated_table_3_id_fkey_1230097 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230091(id)
|
|
||||||
test_colocated_table_3_1230097 | test_colocated_table_3_value_1_fkey_1230097 | FOREIGN KEY (value_1) REFERENCES "Tenant Isolation".test_reference_table_fkey_1230066(id)
|
|
||||||
test_colocated_table_3_1230098 | test_colocated_table_3_id_fkey1_1230098 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_2_1230095(id)
|
|
||||||
test_colocated_table_3_1230098 | test_colocated_table_3_id_fkey_1230098 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230092(id)
|
|
||||||
test_colocated_table_3_1230098 | test_colocated_table_3_value_1_fkey_1230098 | FOREIGN KEY (value_1) REFERENCES "Tenant Isolation".test_reference_table_fkey_1230066(id)
|
|
||||||
test_colocated_table_3_1230099 | test_colocated_table_3_id_fkey1_1230099 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_2_1230096(id)
|
|
||||||
test_colocated_table_3_1230099 | test_colocated_table_3_id_fkey_1230099 | FOREIGN KEY (id) REFERENCES "Tenant Isolation".test_colocated_table_1_1230093(id)
|
|
||||||
test_colocated_table_3_1230099 | test_colocated_table_3_value_1_fkey_1230099 | FOREIGN KEY (value_1) REFERENCES "Tenant Isolation".test_reference_table_fkey_1230066(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 => 'block_writes');
|
|
||||||
?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 => 'block_writes');
|
|
||||||
?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 1;
|
|
||||||
ALTER SEQUENCE pg_catalog.pg_dist_placement_placementid_seq RESTART :last_placement_id;
|
|
|
@ -393,7 +393,7 @@ RESET citus.enable_metadata_sync;
|
||||||
CREATE EVENT TRIGGER abort_drop ON sql_drop
|
CREATE EVENT TRIGGER abort_drop ON sql_drop
|
||||||
EXECUTE PROCEDURE abort_drop_command();
|
EXECUTE PROCEDURE abort_drop_command();
|
||||||
|
|
||||||
\c :master_port
|
\c - postgres - :master_port
|
||||||
-- Disable deferred drop otherwise we will skip the drop and operation will succeed instead of failing.
|
-- Disable deferred drop otherwise we will skip the drop and operation will succeed instead of failing.
|
||||||
ALTER SYSTEM SET citus.defer_drop_after_shard_split TO false;
|
ALTER SYSTEM SET citus.defer_drop_after_shard_split TO false;
|
||||||
SELECT pg_reload_conf();
|
SELECT pg_reload_conf();
|
||||||
|
|
Loading…
Reference in New Issue