CREATE SCHEMA regular_schema;
SET search_path TO regular_schema;
SET citus.next_shard_id TO 1920000;
SET citus.shard_count TO 32;
SET citus.shard_replication_factor TO 1;
SET client_min_messages TO WARNING;
SELECT 1 FROM citus_add_node('localhost', :master_port, groupid => 0);
 ?column?
---------------------------------------------------------------------
        1
(1 row)

SET client_min_messages TO NOTICE;
-- Verify that the UDFs used to sync tenant schema metadata to workers
-- fail on NULL input.
SELECT citus_internal.add_tenant_schema(NULL, 1);
ERROR:  schema_id cannot be NULL
SELECT citus_internal.add_tenant_schema(1, NULL);
ERROR:  colocation_id cannot be NULL
SELECT citus_internal.delete_tenant_schema(NULL);
ERROR:  schema_id cannot be NULL
SELECT citus_internal.unregister_tenant_schema_globally(1, NULL);
ERROR:  schema_name cannot be NULL
SELECT citus_internal.unregister_tenant_schema_globally(NULL, 'text');
ERROR:  schema_id cannot be NULL
-- Verify that citus_internal.unregister_tenant_schema_globally can only
-- be called on schemas that are dropped already.
SELECT citus_internal.unregister_tenant_schema_globally('regular_schema'::regnamespace, 'regular_schema');
ERROR:  schema is expected to be already dropped because this function is only expected to be called from Citus drop hook
SELECT 1 FROM citus_remove_node('localhost', :worker_2_port);
 ?column?
---------------------------------------------------------------------
        1
(1 row)

CREATE TABLE regular_schema.test_table(a int, b text);
SELECT create_distributed_table('regular_schema.test_table', 'a');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

SET citus.enable_schema_based_sharding TO ON;
-- show that regular_schema doesn't show up in pg_dist_schema
SELECT COUNT(*)=0 FROM pg_dist_schema WHERE schemaid::regnamespace::text = 'regular_schema';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

-- empty tenant
CREATE SCHEMA "tenant\'_1";
CREATE SCHEMA IF NOT EXISTS "tenant\'_1";
NOTICE:  schema "tenant\'_1" already exists, skipping
-- non-empty tenant
CREATE SCHEMA "tenant\'_2";
CREATE TABLE "tenant\'_2".test_table(a int, b text);
-- empty tenant
CREATE SCHEMA "tenant\'_3";
CREATE TABLE "tenant\'_3".test_table(a int, b text);
DROP TABLE "tenant\'_3".test_table;
-- add a node after creating tenant schemas
SELECT 1 FROM citus_add_node('localhost', :worker_2_port);
 ?column?
---------------------------------------------------------------------
        1
(1 row)

ALTER SCHEMA "tenant\'_1" RENAME TO tenant_1;
ALTER SCHEMA "tenant\'_2" RENAME TO tenant_2;
ALTER SCHEMA "tenant\'_3" RENAME TO tenant_3;
-- verify that create_distributed_table() and others fail when called on tenant tables
SELECT create_distributed_table('tenant_2.test_table', 'a');
ERROR:  table "test_table" is already distributed
SELECT create_reference_table('tenant_2.test_table');
ERROR:  table "test_table" is already distributed
SELECT citus_add_local_table_to_metadata('tenant_2.test_table');
ERROR:  table "test_table" is already distributed
-- verify we don't allow update_distributed_table_colocation for tenant tables
SELECT update_distributed_table_colocation('tenant_2.test_table', colocate_with => 'none');
ERROR:  tenant_2.test_table is not allowed for update_distributed_table_colocation because it belongs to a distributed schema
-- verify we also don't allow colocate_with a tenant table
SELECT update_distributed_table_colocation('regular_schema.test_table', colocate_with => 'tenant_2.test_table');
ERROR:  tenant_2.test_table is not allowed for colocate_with because it belongs to a distributed schema
-- verify we do not allow undistribute_table for tenant tables
CREATE TABLE tenant_2.undist_table(id int);
SELECT undistribute_table('tenant_2.undist_table');
ERROR:  tenant_2.undist_table is not allowed for undistribute_table because it belongs to a distributed schema
-- verify we don't allow alter_distributed_table for tenant tables
SELECT alter_distributed_table('tenant_2.test_table', colocate_with => 'none');
ERROR:  tenant_2.test_table is not allowed for alter_distributed_table because it belongs to a distributed schema
-- verify we also don't allow colocate_with a tenant table
SELECT alter_distributed_table('regular_schema.test_table', colocate_with => 'tenant_2.test_table');
ERROR:  tenant_2.test_table is not allowed for colocate_with because it belongs to a distributed schema
-- verify we can set tenant table's schema to regular schema
CREATE TABLE tenant_2.test_table2(id int);
ALTER TABLE tenant_2.test_table2 SET SCHEMA regular_schema;
NOTICE:  undistributing table test_table2 in distributed schema tenant_2 before altering its schema
-- verify that regular_schema.test_table2 does not exist in pg_dist_partition
SELECT COUNT(*)=0 FROM pg_dist_partition
WHERE logicalrelid = 'regular_schema.test_table2'::regclass AND
      partmethod = 'n' AND repmodel = 's' AND colocationid > 0;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

-- verify that tenant_2.test_table2 does not exist
SELECT * FROM tenant_2.test_table2;
ERROR:  relation "tenant_2.test_table2" does not exist
-- verify we can set regular table's schema to distributed schema
CREATE TABLE regular_schema.test_table3(id int);
ALTER TABLE regular_schema.test_table3 SET SCHEMA tenant_2;
NOTICE:  Moving test_table3 into distributed schema tenant_2
-- verify that tenant_2.test_table3 is recorded in pg_dist_partition as a single-shard table.
SELECT COUNT(*)=1 FROM pg_dist_partition
WHERE logicalrelid = 'tenant_2.test_table3'::regclass AND
      partmethod = 'n' AND repmodel = 's' AND colocationid > 0;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

-- verify that regular_schema.test_table3 does not exist
SELECT * FROM regular_schema.test_table3;
ERROR:  relation "regular_schema.test_table3" does not exist
-- verify we can set tenant table's schema to another distributed schema
CREATE TABLE tenant_2.test_table4(id int);
ALTER TABLE tenant_2.test_table4 SET SCHEMA tenant_3;
NOTICE:  undistributing table test_table4 in distributed schema tenant_2 before altering its schema
NOTICE:  Moving test_table4 into distributed schema tenant_3
-- verify that tenant_3.test_table4 is recorded in pg_dist_partition as a single-shard table.
SELECT COUNT(*)=1 FROM pg_dist_partition
WHERE logicalrelid = 'tenant_3.test_table4'::regclass AND
      partmethod = 'n' AND repmodel = 's' AND colocationid > 0;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

-- verify that tenant_2.test_table4 does not exist
SELECT * FROM tenant_2.test_table4;
ERROR:  relation "tenant_2.test_table4" does not exist
-- verify that we can put a local table in regular schema into distributed schema
CREATE TABLE regular_schema.pg_local_tbl(id int);
ALTER TABLE regular_schema.pg_local_tbl SET SCHEMA tenant_2;
NOTICE:  Moving pg_local_tbl into distributed schema tenant_2
-- verify that we can put a Citus local table in regular schema into distributed schema
CREATE TABLE regular_schema.citus_local_tbl(id int);
SELECT citus_add_local_table_to_metadata('regular_schema.citus_local_tbl');
 citus_add_local_table_to_metadata
---------------------------------------------------------------------

(1 row)

ALTER TABLE regular_schema.citus_local_tbl SET SCHEMA tenant_2;
NOTICE:  Moving citus_local_tbl into distributed schema tenant_2
-- verify that we do not allow a hash distributed table in regular schema into distributed schema
CREATE TABLE regular_schema.hash_dist_tbl(id int);
SELECT create_distributed_table('regular_schema.hash_dist_tbl', 'id');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

ALTER TABLE regular_schema.hash_dist_tbl SET SCHEMA tenant_2;
ERROR:  distributed schema cannot have distributed tables
HINT:  Undistribute distributed tables before 'ALTER TABLE SET SCHEMA'.
-- verify that we do not allow a reference table in regular schema into distributed schema
CREATE TABLE regular_schema.ref_tbl(id int  PRIMARY KEY);
SELECT create_reference_table('regular_schema.ref_tbl');
 create_reference_table
---------------------------------------------------------------------

(1 row)

ALTER TABLE regular_schema.ref_tbl SET SCHEMA tenant_2;
ERROR:  distributed schema cannot have distributed tables
HINT:  Undistribute distributed tables before 'ALTER TABLE SET SCHEMA'.
-- verify that we can put a table in tenant schema into regular schema
CREATE TABLE tenant_2.tenant_tbl(id int);
ALTER TABLE tenant_2.tenant_tbl SET SCHEMA regular_schema;
NOTICE:  undistributing table tenant_tbl in distributed schema tenant_2 before altering its schema
-- verify that we can put a table in tenant schema into another tenant schema
CREATE TABLE tenant_2.tenant_tbl2(id int);
ALTER TABLE tenant_2.tenant_tbl2 SET SCHEMA tenant_3;
NOTICE:  undistributing table tenant_tbl2 in distributed schema tenant_2 before altering its schema
NOTICE:  Moving tenant_tbl2 into distributed schema tenant_3
-- verify that we do not allow a local table in regular schema into distributed schema if it has foreign key to a non-reference table in another schema
CREATE TABLE regular_schema.pg_local_tbl1(id int PRIMARY KEY);
CREATE TABLE regular_schema.pg_local_tbl2(id int REFERENCES regular_schema.pg_local_tbl1(id));
ALTER TABLE regular_schema.pg_local_tbl2 SET SCHEMA tenant_2;
ERROR:  foreign keys from distributed schemas can only point to the same distributed schema or reference tables in regular schemas
DETAIL:  "tenant_2.pg_local_tbl2" references "regular_schema.pg_local_tbl1" via foreign key constraint "pg_local_tbl2_id_fkey"
-- verify that we allow a local table in regular schema into distributed schema if it has foreign key to a reference table in another schema
CREATE TABLE regular_schema.pg_local_tbl3(id int REFERENCES regular_schema.ref_tbl(id));
ALTER TABLE regular_schema.pg_local_tbl3 SET SCHEMA tenant_2;
NOTICE:  Moving pg_local_tbl3 into distributed schema tenant_2
-- verify that we do not allow a table in tenant schema into regular schema if it has foreign key to/from another table in the same schema
CREATE TABLE tenant_2.tenant_tbl1(id int PRIMARY KEY);
CREATE TABLE tenant_2.tenant_tbl2(id int REFERENCES tenant_2.tenant_tbl1(id));
ALTER TABLE tenant_2.tenant_tbl1 SET SCHEMA regular_schema;
ERROR:  set schema is not allowed for table tenant_tbl1 in distributed schema tenant_2
DETAIL:  distributed schemas cannot have foreign keys from/to local tables or different schema
ALTER TABLE tenant_2.tenant_tbl2 SET SCHEMA regular_schema;
ERROR:  set schema is not allowed for table tenant_tbl2 in distributed schema tenant_2
DETAIL:  distributed schemas cannot have foreign keys from/to local tables or different schema
-- verify that we do not allow a table in distributed schema into another distributed schema if it has foreign key to/from another table in the same schema
CREATE TABLE tenant_2.tenant_tbl3(id int PRIMARY KEY);
CREATE TABLE tenant_2.tenant_tbl4(id int REFERENCES tenant_2.tenant_tbl3(id));
ALTER TABLE tenant_2.tenant_tbl3 SET SCHEMA tenant_3;
ERROR:  set schema is not allowed for table tenant_tbl3 in distributed schema tenant_2
DETAIL:  distributed schemas cannot have foreign keys from/to local tables or different schema
ALTER TABLE tenant_2.tenant_tbl4 SET SCHEMA tenant_3;
ERROR:  set schema is not allowed for table tenant_tbl4 in distributed schema tenant_2
DETAIL:  distributed schemas cannot have foreign keys from/to local tables or different schema
-- alter set non-existent schema
ALTER TABLE tenant_2.test_table SET SCHEMA ghost_schema;
ERROR:  schema "ghost_schema" does not exist
ALTER TABLE IF EXISTS tenant_2.test_table SET SCHEMA ghost_schema;
ERROR:  schema "ghost_schema" does not exist
-- alter set non-existent table
ALTER TABLE tenant_2.ghost_table SET SCHEMA ghost_schema;
ERROR:  relation "tenant_2.ghost_table" does not exist
ALTER TABLE IF EXISTS tenant_2.ghost_table SET SCHEMA ghost_schema;
NOTICE:  relation "ghost_table" does not exist, skipping
-- (on coordinator) verify that colocation id is set for empty tenants too
SELECT colocationid > 0 FROM pg_dist_schema
WHERE schemaid::regnamespace::text IN ('tenant_1', 'tenant_3');
 ?column?
---------------------------------------------------------------------
 t
 t
(2 rows)

-- (on workers) verify that colocation id is set for empty tenants too
SELECT result FROM run_command_on_workers($$
    SELECT array_agg(colocationid > 0) FROM pg_dist_schema
    WHERE schemaid::regnamespace::text IN ('tenant_1', 'tenant_3');
$$);
 result
---------------------------------------------------------------------
 {t,t}
 {t,t}
(2 rows)

-- Verify that tenant_2.test_table is recorded in pg_dist_partition as a
-- single-shard table.
SELECT COUNT(*)=1 FROM pg_dist_partition
WHERE logicalrelid = 'tenant_2.test_table'::regclass AND
      partmethod = 'n' AND repmodel = 's' AND colocationid > 0;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

-- (on coordinator) verify that colocation id is properly set for non-empty tenant schema
SELECT colocationid = (
    SELECT colocationid FROM pg_dist_partition WHERE logicalrelid = 'tenant_2.test_table'::regclass
)
FROM pg_dist_schema
WHERE schemaid::regnamespace::text = 'tenant_2';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

-- (on workers) verify that colocation id is properly set for non-empty tenant schema
SELECT result FROM run_command_on_workers($$
    SELECT colocationid = (
        SELECT colocationid FROM pg_dist_partition WHERE logicalrelid = 'tenant_2.test_table'::regclass
    )
    FROM pg_dist_schema
    WHERE schemaid::regnamespace::text = 'tenant_2';
$$);
 result
---------------------------------------------------------------------
 t
 t
(2 rows)

-- create a tenant table for tenant_1 after add_node
CREATE TABLE tenant_1.test_table(a int, b text);
-- (on coordinator) verify that colocation id is properly set for now-non-empty tenant schema
SELECT colocationid = (
    SELECT colocationid FROM pg_dist_partition WHERE logicalrelid = 'tenant_1.test_table'::regclass
)
FROM pg_dist_schema
WHERE schemaid::regnamespace::text = 'tenant_1';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

-- (on workers) verify that colocation id is properly set for now-non-empty tenant schema
SELECT result FROM run_command_on_workers($$
    SELECT colocationid = (
        SELECT colocationid FROM pg_dist_partition WHERE logicalrelid = 'tenant_1.test_table'::regclass
    )
    FROM pg_dist_schema
    WHERE schemaid::regnamespace::text = 'tenant_1';
$$);
 result
---------------------------------------------------------------------
 t
 t
(2 rows)

-- verify that tenant_1 and tenant_2 have different colocation ids
SELECT COUNT(DISTINCT(colocationid))=2 FROM pg_dist_schema
WHERE schemaid::regnamespace::text IN ('tenant_1', 'tenant_2');
 ?column?
---------------------------------------------------------------------
 t
(1 row)

-- verify that we don't allow creating tenant tables via CREATE SCHEMA command
CREATE SCHEMA schema_using_schema_elements CREATE TABLE test_table(a int, b text);
ERROR:  cannot create distributed schema and table in a single statement
HINT:  SET citus.enable_schema_based_sharding TO off, or create the schema and table in separate commands.
CREATE SCHEMA tenant_4;
CREATE TABLE tenant_4.tbl_1(a int, b text);
CREATE TABLE tenant_4.tbl_2(a int, b text);
-- verify that we don't allow creating a foreign table in a tenant schema, with a nice error message
CREATE FOREIGN TABLE tenant_4.foreign_table (
  id bigint not null,
  full_name text not null default ''
) SERVER fake_fdw_server OPTIONS (encoding 'utf-8', compression 'true', table_name 'foreign_table');
ERROR:  cannot create a foreign table in a distributed schema
-- verify that we don't allow creating a foreign table in a tenant schema
CREATE TEMPORARY TABLE tenant_4.temp_table (a int, b text);
ERROR:  cannot create temporary relation in non-temporary schema
CREATE TABLE tenant_4.partitioned_table(a int, b text, PRIMARY KEY (a)) PARTITION BY RANGE (a);
CREATE TABLE tenant_4.partitioned_table_child_1 PARTITION OF tenant_4.partitioned_table FOR VALUES FROM (1) TO (2);
CREATE TABLE tenant_4.another_partitioned_table(a int, b text, FOREIGN KEY (a) REFERENCES tenant_4.partitioned_table(a)) PARTITION BY RANGE (a);
CREATE TABLE tenant_4.another_partitioned_table_child PARTITION OF tenant_4.another_partitioned_table FOR VALUES FROM (1) TO (2);
-- verify that we allow creating partitioned tables in a tenant schema
SELECT COUNT(*)=1 FROM pg_dist_partition
WHERE logicalrelid = 'tenant_4.partitioned_table_child_1'::regclass AND
       partmethod = 'n' AND repmodel = 's' AND colocationid = (
        SELECT colocationid FROM pg_dist_partition
        WHERE logicalrelid = 'tenant_4.partitioned_table'::regclass);
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT EXISTS(
    SELECT 1
    FROM pg_inherits
    WHERE inhrelid = 'tenant_4.partitioned_table_child_1'::regclass AND
          inhparent = 'tenant_4.partitioned_table'::regclass
) AS is_partition;
 is_partition
---------------------------------------------------------------------
 t
(1 row)

SELECT COUNT(*)=1 FROM pg_dist_partition
WHERE logicalrelid = 'tenant_4.another_partitioned_table_child'::regclass AND
       partmethod = 'n' AND repmodel = 's' AND colocationid = (
        SELECT colocationid FROM pg_dist_partition
        WHERE logicalrelid = 'tenant_4.another_partitioned_table'::regclass);
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT EXISTS(
    SELECT 1
    FROM pg_inherits
    WHERE inhrelid = 'tenant_4.another_partitioned_table_child'::regclass AND
          inhparent = 'tenant_4.another_partitioned_table'::regclass
) AS is_partition;
 is_partition
---------------------------------------------------------------------
 t
(1 row)

-- verify the foreign key between parents
SELECT EXISTS(
    SELECT 1
    FROM pg_constraint
    WHERE conrelid = 'tenant_4.another_partitioned_table'::regclass AND
          confrelid = 'tenant_4.partitioned_table'::regclass AND
          contype = 'f'
) AS foreign_key_exists;
 foreign_key_exists
---------------------------------------------------------------------
 t
(1 row)

INSERT INTO tenant_4.another_partitioned_table VALUES (1, 'a');
ERROR:  insert or update on table "another_partitioned_table_child_1920088" violates foreign key constraint "another_partitioned_table_a_fkey_1920087"
DETAIL:  Key (a)=(1) is not present in table "partitioned_table_1920085".
CONTEXT:  while executing command on localhost:xxxxx
INSERT INTO tenant_4.partitioned_table VALUES (1, 'a');
INSERT INTO tenant_4.another_partitioned_table VALUES (1, 'a');
CREATE SCHEMA tenant_5;
CREATE TABLE tenant_5.tbl_1(a int, b text);
CREATE TABLE tenant_5.partitioned_table(a int, b text) PARTITION BY RANGE (a);
-- verify that we don't allow creating a partition table that is child of a partitioned table in a different tenant schema
CREATE TABLE tenant_4.partitioned_table_child_2 PARTITION OF tenant_5.partitioned_table FOR VALUES FROM (1) TO (2);
ERROR:  partitioning within a distributed schema is not supported when the parent and the child are in different schemas
-- verify that we don't allow creating a local partition table that is child of a tenant partitioned table
CREATE TABLE regular_schema.local_child_table PARTITION OF tenant_5.partitioned_table FOR VALUES FROM (1) TO (2);
ERROR:  partitioning within a distributed schema is not supported when the parent and the child are in different schemas
SET citus.use_citus_managed_tables TO ON;
CREATE TABLE regular_schema.local_child_table PARTITION OF tenant_5.partitioned_table FOR VALUES FROM (1) TO (2);
ERROR:  partitioning within a distributed schema is not supported when the parent and the child are in different schemas
RESET citus.use_citus_managed_tables;
CREATE TABLE regular_schema.local_partitioned_table(a int, b text) PARTITION BY RANGE (a);
CREATE TABLE regular_schema.citus_local_partitioned_table(a int, b text) PARTITION BY RANGE (a);
SELECT citus_add_local_table_to_metadata('regular_schema.citus_local_partitioned_table');
 citus_add_local_table_to_metadata
---------------------------------------------------------------------

(1 row)

CREATE TABLE regular_schema.dist_partitioned_table(a int, b text) PARTITION BY RANGE (a);
SELECT create_distributed_table('regular_schema.dist_partitioned_table', 'a');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- verify that we don't allow creating a partition table that is child of a non-tenant partitioned table
CREATE TABLE tenant_4.partitioned_table_child_2 PARTITION OF regular_schema.local_partitioned_table FOR VALUES FROM (1) TO (2);
ERROR:  partitioning within a distributed schema is not supported when the parent and the child are in different schemas
CREATE TABLE tenant_4.partitioned_table_child_2 PARTITION OF regular_schema.citus_local_partitioned_table FOR VALUES FROM (1) TO (2);
ERROR:  partitioning within a distributed schema is not supported when the parent and the child are in different schemas
CREATE TABLE tenant_4.partitioned_table_child_2 PARTITION OF regular_schema.dist_partitioned_table FOR VALUES FROM (1) TO (2);
ERROR:  partitioning within a distributed schema is not supported when the parent and the child are in different schemas
CREATE TABLE tenant_4.parent_attach_test(a int, b text) PARTITION BY RANGE (a);
CREATE TABLE tenant_4.child_attach_test(a int, b text);
CREATE TABLE tenant_5.parent_attach_test(a int, b text) PARTITION BY RANGE (a);
CREATE TABLE tenant_5.child_attach_test(a int, b text);
CREATE TABLE regular_schema.parent_attach_test_local(a int, b text) PARTITION BY RANGE (a);
CREATE TABLE regular_schema.parent_attach_test_citus_local(a int, b text) PARTITION BY RANGE (a);
SELECT citus_add_local_table_to_metadata('regular_schema.parent_attach_test_citus_local');
 citus_add_local_table_to_metadata
---------------------------------------------------------------------

(1 row)

CREATE TABLE regular_schema.parent_attach_test_dist(a int, b text) PARTITION BY RANGE (a);
SELECT create_distributed_table('regular_schema.parent_attach_test_dist', 'a');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

CREATE TABLE regular_schema.child_attach_test_local(a int, b text);
CREATE TABLE regular_schema.child_attach_test_citus_local(a int, b text);
SELECT citus_add_local_table_to_metadata('regular_schema.child_attach_test_citus_local');
 citus_add_local_table_to_metadata
---------------------------------------------------------------------

(1 row)

CREATE TABLE regular_schema.child_attach_test_dist(a int, b text);
SELECT create_distributed_table('regular_schema.child_attach_test_dist', 'a');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- verify that we don't allow attaching a tenant table into a tenant partitioned table, if they are not in the same schema
ALTER TABLE tenant_4.parent_attach_test ATTACH PARTITION tenant_5.child_attach_test FOR VALUES FROM (1) TO (2);
ERROR:  partitioning within a distributed schema is not supported when the parent and the child are in different schemas
-- verify that we don't allow attaching a non-tenant table into a tenant partitioned table
ALTER TABLE tenant_4.parent_attach_test ATTACH PARTITION regular_schema.child_attach_test_local FOR VALUES FROM (1) TO (2);
ERROR:  partitioning within a distributed schema is not supported when the parent and the child are in different schemas
ALTER TABLE tenant_4.parent_attach_test ATTACH PARTITION regular_schema.child_attach_test_citus_local FOR VALUES FROM (1) TO (2);
ERROR:  partitioning within a distributed schema is not supported when the parent and the child are in different schemas
ALTER TABLE tenant_4.parent_attach_test ATTACH PARTITION regular_schema.child_attach_test_dist FOR VALUES FROM (1) TO (2);
ERROR:  partitioning within a distributed schema is not supported when the parent and the child are in different schemas
-- verify that we don't allow attaching a tenant table into a non-tenant partitioned table
ALTER TABLE regular_schema.parent_attach_test_local ATTACH PARTITION tenant_4.child_attach_test FOR VALUES FROM (1) TO (2);
ERROR:  partitioning within a distributed schema is not supported when the parent and the child are in different schemas
ALTER TABLE regular_schema.parent_attach_test_citus_local ATTACH PARTITION tenant_4.child_attach_test FOR VALUES FROM (1) TO (2);
ERROR:  partitioning within a distributed schema is not supported when the parent and the child are in different schemas
ALTER TABLE regular_schema.parent_attach_test_dist ATTACH PARTITION tenant_4.child_attach_test FOR VALUES FROM (1) TO (2);
ERROR:  partitioning within a distributed schema is not supported when the parent and the child are in different schemas
ALTER TABLE tenant_4.parent_attach_test ATTACH PARTITION tenant_4.child_attach_test FOR VALUES FROM (1) TO (2);
-- verify that we don't allow multi-level partitioning on tenant tables
CREATE TABLE tenant_4.multi_level_test(a int, b text) PARTITION BY RANGE (a);
ALTER TABLE tenant_4.parent_attach_test ATTACH PARTITION tenant_4.multi_level_test FOR VALUES FROM (1) TO (2);
ERROR:  Citus doesn't support multi-level partitioned tables
DETAIL:  Relation "multi_level_test" is partitioned table itself and it is also partition of relation "parent_attach_test".
-- verify that we allow attaching a tenant table into a tenant partitioned table, if they are in the same schema
SELECT COUNT(*)=1 FROM pg_dist_partition
WHERE logicalrelid = 'tenant_4.parent_attach_test'::regclass AND
       partmethod = 'n' AND repmodel = 's' AND colocationid = (
        SELECT colocationid FROM pg_dist_partition
        WHERE logicalrelid = 'tenant_4.child_attach_test'::regclass);
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT EXISTS(
    SELECT 1
    FROM pg_inherits
    WHERE inhrelid = 'tenant_4.child_attach_test'::regclass AND
          inhparent = 'tenant_4.parent_attach_test'::regclass
) AS is_partition;
 is_partition
---------------------------------------------------------------------
 t
(1 row)

-- errors out because shard replication factor > 1
SET citus.shard_replication_factor TO 2;
CREATE TABLE tenant_4.tbl_3 AS SELECT 1 AS a, 'text' as b;
ERROR:  could not create single shard table: citus.shard_replication_factor is greater than 1
HINT:  Consider setting citus.shard_replication_factor to 1 and try again
SET citus.shard_replication_factor TO 1;
-- verify that we allow creating tenant tables by using CREATE TABLE AS / SELECT INTO commands
CREATE TABLE tenant_4.tbl_3 AS SELECT 1 AS a, 'text' as b;
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_4.tbl_3$$)
CREATE TEMP TABLE IF NOT EXISTS tenant_4.tbl_4 AS SELECT 1 as a, 'text' as b;
ERROR:  cannot create temporary relation in non-temporary schema
CREATE UNLOGGED TABLE IF NOT EXISTS tenant_4.tbl_4 AS SELECT 1 as a, 'text' as b WITH NO DATA;
-- the same command, no changes because of IF NOT EXISTS
CREATE UNLOGGED TABLE IF NOT EXISTS tenant_4.tbl_4 AS SELECT 1 as a, 'text' as b WITH NO DATA;
NOTICE:  relation "tbl_4" already exists, skipping
SELECT 1 as a, 'text' as b INTO tenant_4.tbl_5;
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_4.tbl_5$$)
-- verify we can query the newly created tenant tables
SELECT * FROM tenant_4.tbl_3;
 a |  b
---------------------------------------------------------------------
 1 | text
(1 row)

SELECT COUNT(*) FROM tenant_4.tbl_5;
 count
---------------------------------------------------------------------
     1
(1 row)

CREATE TYPE employee_type AS (name text, salary numeric);
-- verify that we don't allow creating tenant tables by using CREATE TABLE OF commands
CREATE TABLE tenant_4.employees OF employee_type (
    PRIMARY KEY (name),
    salary WITH OPTIONS DEFAULT 1000
);
ERROR:  cannot create tables in a distributed schema using CREATE TABLE OF syntax
-- verify that we act accordingly when if not exists is used
CREATE TABLE IF NOT EXISTS tenant_4.tbl_6(a int, b text);
CREATE TABLE IF NOT EXISTS tenant_4.tbl_6(a int, b text);
NOTICE:  relation "tbl_6" already exists, skipping
SELECT logicalrelid, partmethod
    FROM pg_dist_partition
    WHERE logicalrelid::text LIKE 'tenant_4.tbl%'
    ORDER BY logicalrelid;
  logicalrelid  | partmethod
---------------------------------------------------------------------
 tenant_4.tbl_1 | n
 tenant_4.tbl_2 | n
 tenant_4.tbl_3 | n
 tenant_4.tbl_4 | n
 tenant_4.tbl_5 | n
 tenant_4.tbl_6 | n
(6 rows)

CREATE TABLE regular_schema.local(a int, b text);
CREATE TABLE regular_schema.citus_local(a int, b text);
SELECT citus_add_local_table_to_metadata('regular_schema.citus_local');
 citus_add_local_table_to_metadata
---------------------------------------------------------------------

(1 row)

CREATE TABLE regular_schema.dist(a int, b text);
SELECT create_distributed_table('regular_schema.dist', 'a');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- verify that we can create a table LIKE another table
CREATE TABLE tenant_5.test_table_like_1(LIKE tenant_5.tbl_1); -- using a table from the same schema
CREATE TABLE tenant_5.test_table_like_2(LIKE tenant_4.tbl_1); -- using a table from another schema
CREATE TABLE tenant_5.test_table_like_3(LIKE regular_schema.local); -- using a local table
CREATE TABLE tenant_5.test_table_like_4(LIKE regular_schema.citus_local); -- using a citus local table
CREATE TABLE tenant_5.test_table_like_5(LIKE regular_schema.dist); -- using a distributed table
-- verify that all of them are converted to tenant tables
SELECT COUNT(*) = 5
FROM pg_dist_partition
WHERE logicalrelid::text LIKE 'tenant_5.test_table_like_%' AND
      partmethod = 'n' AND repmodel = 's' AND colocationid = (
        SELECT colocationid FROM pg_dist_schema
        WHERE schemaid::regnamespace::text = 'tenant_5'
        );
 ?column?
---------------------------------------------------------------------
 t
(1 row)

CREATE TABLE regular_schema.local_table_using_like(LIKE tenant_5.tbl_1);
-- verify that regular_schema.local_table_using_like is not a tenant table
SELECT COUNT(*) = 0 FROM pg_dist_partition
WHERE logicalrelid = 'regular_schema.local_table_using_like'::regclass;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

-- verify that INHERITS syntax is not supported when creating a tenant table
CREATE TABLE tenant_5.test_table_inherits_1(x int) INHERITS (tenant_5.tbl_1); -- using a table from the same schema
ERROR:  tables in a distributed schema cannot inherit or be inherited
CREATE TABLE tenant_5.test_table_inherits_2(x int) INHERITS (tenant_4.tbl_1); -- using a table from another schema
ERROR:  tables in a distributed schema cannot inherit or be inherited
CREATE TABLE tenant_5.test_table_inherits_3(x int) INHERITS (regular_schema.local); -- using a local table
ERROR:  tables in a distributed schema cannot inherit or be inherited
CREATE TABLE tenant_5.test_table_inherits_4(x int) INHERITS (regular_schema.citus_local); -- using a citus local table
ERROR:  tables in a distributed schema cannot inherit or be inherited
CREATE TABLE tenant_5.test_table_inherits_5(x int) INHERITS (regular_schema.dist); -- using a distributed table
ERROR:  tables in a distributed schema cannot inherit or be inherited
-- verify that INHERITS syntax is not supported when creating a local table based on a tenant table
CREATE TABLE regular_schema.local_table_using_inherits(x int) INHERITS (tenant_5.tbl_1);
ERROR:  tables in a distributed schema cannot inherit or be inherited
CREATE TABLE tenant_5.tbl_2(a int, b text);
CREATE SCHEMA "CiTuS.TeeN_108";
ALTER SCHEMA "CiTuS.TeeN_108" RENAME TO citus_teen_proper;
SELECT schemaid AS citus_teen_schemaid FROM pg_dist_schema WHERE schemaid::regnamespace::text = 'citus_teen_proper' \gset
SELECT colocationid AS citus_teen_colocationid FROM pg_dist_schema WHERE schemaid::regnamespace::text = 'citus_teen_proper' \gset
SELECT result FROM run_command_on_workers($$
    SELECT schemaid INTO citus_teen_schemaid FROM pg_dist_schema
    WHERE schemaid::regnamespace::text = 'citus_teen_proper'
$$);
  result
---------------------------------------------------------------------
 SELECT 1
 SELECT 1
(2 rows)

-- (on coordinator) verify that colocation id is set for the tenant with a weird name too
SELECT :citus_teen_colocationid > 0;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

-- (on workers) verify that the same colocation id is used on workers too
SELECT format(
    'SELECT result FROM run_command_on_workers($$
        SELECT COUNT(*)=1 FROM pg_dist_schema
        WHERE schemaid::regnamespace::text = ''citus_teen_proper'' AND
              colocationid = %s;
    $$);',
:citus_teen_colocationid) AS verify_workers_query \gset
:verify_workers_query
 result
---------------------------------------------------------------------
 t
 t
(2 rows)

ALTER SCHEMA citus_teen_proper RENAME TO "CiTuS.TeeN_108";
SET citus.enable_schema_based_sharding TO OFF;
-- Show that the tables created in tenant schemas are considered to be
-- tenant tables even if the GUC was set to off when creating the table.
CREATE TABLE tenant_5.tbl_3(a int, b text);
SELECT COUNT(*)=1 FROM pg_dist_partition WHERE logicalrelid = 'tenant_5.tbl_3'::regclass;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SET citus.enable_schema_based_sharding TO ON;
-- Verify that tables that belong to tenant_4 and tenant_5 are stored on
-- different worker nodes due to order we followed when creating first tenant
-- tables in each of them.
SELECT COUNT(DISTINCT(nodename, nodeport))=2 FROM citus_shards
WHERE table_name IN ('tenant_4.tbl_1'::regclass, 'tenant_5.tbl_1'::regclass);
 ?column?
---------------------------------------------------------------------
 t
(1 row)

-- show that all the tables in tenant_4 are colocated with each other.
SELECT COUNT(DISTINCT(colocationid))=1 FROM pg_dist_partition
WHERE logicalrelid::regclass::text LIKE 'tenant_4.%';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

-- verify the same for tenant_5 too
SELECT COUNT(DISTINCT(colocationid))=1 FROM pg_dist_partition
WHERE logicalrelid::regclass::text LIKE 'tenant_5.%';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT schemaid AS tenant_4_schemaid FROM pg_dist_schema WHERE schemaid::regnamespace::text = 'tenant_4' \gset
SELECT colocationid AS tenant_4_colocationid FROM pg_dist_schema WHERE schemaid::regnamespace::text = 'tenant_4' \gset
SELECT result FROM run_command_on_workers($$
    SELECT schemaid INTO tenant_4_schemaid FROM pg_dist_schema
    WHERE schemaid::regnamespace::text = 'tenant_4'
$$);
  result
---------------------------------------------------------------------
 SELECT 1
 SELECT 1
(2 rows)

SET client_min_messages TO WARNING;
-- Rename it to a name that contains a single quote to verify that we properly
-- escape its name when sending the command to delete the pg_dist_schema
-- entry on workers.
ALTER SCHEMA tenant_4 RENAME TO "tenant\'_4";
DROP SCHEMA "tenant\'_4", "CiTuS.TeeN_108" CASCADE;
SET client_min_messages TO NOTICE;
-- (on coordinator) Verify that dropping a tenant schema deletes the associated
-- pg_dist_schema entry and pg_dist_colocation too.
SELECT COUNT(*)=0 FROM pg_dist_schema WHERE schemaid = :tenant_4_schemaid;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT COUNT(*)=0 FROM pg_dist_colocation WHERE colocationid = :tenant_4_colocationid;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT COUNT(*)=0 FROM pg_dist_schema WHERE schemaid = :citus_teen_schemaid;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT COUNT(*)=0 FROM pg_dist_colocation WHERE colocationid = :citus_teen_colocationid;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

-- (on workers) Verify that dropping a tenant schema deletes the associated
-- pg_dist_schema entry and pg_dist_colocation too.
SELECT result FROM run_command_on_workers($$
    SELECT COUNT(*)=0 FROM pg_dist_schema
    WHERE schemaid = (SELECT schemaid FROM tenant_4_schemaid)
$$);
 result
---------------------------------------------------------------------
 t
 t
(2 rows)

SELECT result FROM run_command_on_workers($$
    SELECT COUNT(*)=0 FROM pg_dist_schema
    WHERE schemaid = (SELECT schemaid FROM citus_teen_schemaid)
$$);
 result
---------------------------------------------------------------------
 t
 t
(2 rows)

SELECT format(
    'SELECT result FROM run_command_on_workers($$
        SELECT COUNT(*)=0 FROM pg_dist_colocation WHERE colocationid = %s;
    $$);',
:tenant_4_colocationid) AS verify_workers_query \gset
:verify_workers_query
 result
---------------------------------------------------------------------
 t
 t
(2 rows)

SELECT result FROM run_command_on_workers($$
    DROP TABLE tenant_4_schemaid
$$);
   result
---------------------------------------------------------------------
 DROP TABLE
 DROP TABLE
(2 rows)

SELECT format(
    'SELECT result FROM run_command_on_workers($$
        SELECT COUNT(*)=0 FROM pg_dist_colocation WHERE colocationid = %s;
    $$);',
:citus_teen_colocationid) AS verify_workers_query \gset
:verify_workers_query
 result
---------------------------------------------------------------------
 t
 t
(2 rows)

SELECT result FROM run_command_on_workers($$
    DROP TABLE citus_teen_schemaid
$$);
   result
---------------------------------------------------------------------
 DROP TABLE
 DROP TABLE
(2 rows)

-- show that we don't allow colocating a Citus table with a tenant table
CREATE TABLE regular_schema.null_shard_key_1(a int, b text);
SELECT create_distributed_table('regular_schema.null_shard_key_1', null, colocate_with => 'tenant_5.tbl_2');
ERROR:  cannot colocate tables tbl_2 and null_shard_key_1
DETAIL:  Cannot colocate tables with distributed schema tables by using colocate_with option.
HINT:  Consider using "CREATE TABLE" statement to create this table as a single-shard distributed table in the same schema to automatically colocate it with tenant_5.tbl_2
SELECT create_distributed_table('regular_schema.null_shard_key_1', 'a', colocate_with => 'tenant_5.tbl_2');
ERROR:  cannot colocate tables tbl_2 and null_shard_key_1
DETAIL:  Distribution column types don't match for tbl_2 and null_shard_key_1.
CREATE TABLE regular_schema.null_shard_key_table_2(a int, b text);
SELECT create_distributed_table('regular_schema.null_shard_key_table_2', null);
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- Show that we don't chose to colocate regular single-shard tables with
-- tenant tables by default.
SELECT * FROM pg_dist_schema WHERE colocationid = (
    SELECT colocationid FROM pg_dist_partition WHERE logicalrelid = 'regular_schema.null_shard_key_table_2'::regclass
);
 schemaid | colocationid
---------------------------------------------------------------------
(0 rows)

-- save the colocation id used for tenant_5
SELECT colocationid AS tenant_5_old_colocationid FROM pg_dist_schema
WHERE schemaid::regnamespace::text = 'tenant_5' \gset
-- drop all the tables that belong to tenant_5 and create a new one
DROP TABLE tenant_5.tbl_1, tenant_5.tbl_2, tenant_5.tbl_3;
CREATE TABLE tenant_5.tbl_4(a int, b text);
-- (on coordinator) verify that tenant_5 is still associated with the same colocation id
SELECT colocationid = :tenant_5_old_colocationid FROM pg_dist_schema
WHERE schemaid::regnamespace::text = 'tenant_5';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

-- (on workers) verify that tenant_5 is still associated with the same colocation id
SELECT format(
    'SELECT result FROM run_command_on_workers($$
        SELECT colocationid = %s FROM pg_dist_schema
        WHERE schemaid::regnamespace::text = ''tenant_5'';
    $$);',
:tenant_5_old_colocationid) AS verify_workers_query \gset
:verify_workers_query
 result
---------------------------------------------------------------------
 t
 t
(2 rows)

SELECT schemaid AS tenant_1_schemaid FROM pg_dist_schema WHERE schemaid::regnamespace::text = 'tenant_1' \gset
SELECT colocationid AS tenant_1_colocationid FROM pg_dist_schema WHERE schemaid::regnamespace::text = 'tenant_1' \gset
SELECT schemaid AS tenant_2_schemaid FROM pg_dist_schema WHERE schemaid::regnamespace::text = 'tenant_2' \gset
SELECT colocationid AS tenant_2_colocationid FROM pg_dist_schema WHERE schemaid::regnamespace::text = 'tenant_2' \gset
SELECT result FROM run_command_on_workers($$
    SELECT schemaid INTO tenant_1_schemaid FROM pg_dist_schema
    WHERE schemaid::regnamespace::text = 'tenant_1'
$$);
  result
---------------------------------------------------------------------
 SELECT 1
 SELECT 1
(2 rows)

SELECT result FROM run_command_on_workers($$
    SELECT schemaid INTO tenant_2_schemaid FROM pg_dist_schema
    WHERE schemaid::regnamespace::text = 'tenant_2'
$$);
  result
---------------------------------------------------------------------
 SELECT 1
 SELECT 1
(2 rows)

SET client_min_messages TO WARNING;
SET citus.enable_schema_based_sharding TO OFF;
DROP SCHEMA tenant_1 CASCADE;
CREATE ROLE test_non_super_user;
ALTER ROLE test_non_super_user NOSUPERUSER;
ALTER SCHEMA tenant_2 OWNER TO non_existing_role;
ERROR:  role "non_existing_role" does not exist
ALTER SCHEMA tenant_2 OWNER TO test_non_super_user;
SELECT pg_get_userbyid(nspowner) AS schema_owner
    FROM pg_namespace
    WHERE nspname = 'tenant_2';
    schema_owner
---------------------------------------------------------------------
 test_non_super_user
(1 row)

select result from run_command_on_workers ($$
  SELECT pg_get_userbyid(nspowner) AS schema_owner
  FROM pg_namespace
  WHERE nspname = 'tenant_2'
$$);
       result
---------------------------------------------------------------------
 test_non_super_user
 test_non_super_user
(2 rows)

DROP OWNED BY test_non_super_user CASCADE;
DROP ROLE test_non_super_user;
SET client_min_messages TO NOTICE;
-- (on coordinator) Verify that dropping a tenant schema always deletes
-- the associated pg_dist_schema entry even if the the schema was
-- dropped while the GUC was set to off.
SELECT COUNT(*)=0 FROM pg_dist_schema WHERE schemaid IN (:tenant_1_schemaid, :tenant_2_schemaid);
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT COUNT(*)=0 FROM pg_dist_colocation WHERE colocationid IN (:tenant_1_colocationid, :tenant_2_colocationid);
 ?column?
---------------------------------------------------------------------
 t
(1 row)

-- (on workers) Verify that dropping a tenant schema always deletes
-- the associated pg_dist_schema entry even if the the schema was
-- dropped while the GUC was set to off.
SELECT result FROM run_command_on_workers($$
    SELECT COUNT(*)=0 FROM pg_dist_schema
    WHERE schemaid IN (SELECT schemaid FROM tenant_1_schemaid UNION SELECT schemaid FROM tenant_2_schemaid)
$$);
 result
---------------------------------------------------------------------
 t
 t
(2 rows)

SELECT format(
    'SELECT result FROM run_command_on_workers($$
        SELECT COUNT(*)=0 FROM pg_dist_colocation WHERE colocationid IN (%s, %s);
    $$);',
:tenant_1_colocationid, :tenant_2_colocationid) AS verify_workers_query \gset
:verify_workers_query
 result
---------------------------------------------------------------------
 t
 t
(2 rows)

SELECT result FROM run_command_on_workers($$
    DROP TABLE tenant_1_schemaid
$$);
   result
---------------------------------------------------------------------
 DROP TABLE
 DROP TABLE
(2 rows)

SELECT result FROM run_command_on_workers($$
    DROP TABLE tenant_2_schemaid
$$);
   result
---------------------------------------------------------------------
 DROP TABLE
 DROP TABLE
(2 rows)

SET citus.enable_schema_based_sharding TO ON;
SET client_min_messages TO NOTICE;
-- show that all schemaid values are unique and non-null in pg_dist_schema
SELECT COUNT(*)=0 FROM pg_dist_schema WHERE schemaid IS NULL;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT (SELECT COUNT(*) FROM pg_dist_schema) =
       (SELECT COUNT(DISTINCT(schemaid)) FROM pg_dist_schema);
 ?column?
---------------------------------------------------------------------
 t
(1 row)

-- show that all colocationid values are unique and non-null in pg_dist_schema
SELECT COUNT(*)=0 FROM pg_dist_schema WHERE colocationid IS NULL;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT (SELECT COUNT(*) FROM pg_dist_schema) =
       (SELECT COUNT(DISTINCT(colocationid)) FROM pg_dist_schema);
 ?column?
---------------------------------------------------------------------
 t
(1 row)

CREATE TABLE public.cannot_be_a_tenant_table(a int, b text);
-- show that we don't consider public schema as a tenant schema
SELECT COUNT(*)=0 FROM pg_dist_schema WHERE schemaid::regnamespace::text = 'public';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

DROP TABLE public.cannot_be_a_tenant_table;
BEGIN;
    ALTER SCHEMA public RENAME TO public_renamed;
    CREATE SCHEMA public;
    -- Show that we don't consider public schema as a tenant schema,
    -- even if it's recreated.
    SELECT COUNT(*)=0 FROM pg_dist_schema WHERE schemaid::regnamespace::text = 'public';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

ROLLBACK;
CREATE TEMPORARY TABLE temp_table(a int, b text);
-- show that we don't consider temporary schemas as tenant schemas
SELECT COUNT(*)=0 FROM pg_dist_schema WHERE schemaid::regnamespace::text = '%pg_temp%';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

DROP TABLE temp_table;
-- test creating a tenant schema and a tenant table for it in the same transaction
BEGIN;
    CREATE SCHEMA tenant_7;
    CREATE TABLE tenant_7.tbl_1(a int, b text);
    CREATE TABLE tenant_7.tbl_2(a int, b text);
    SELECT colocationid = (
        SELECT colocationid FROM pg_dist_partition WHERE logicalrelid = 'tenant_7.tbl_1'::regclass
    )
    FROM pg_dist_schema
    WHERE schemaid::regnamespace::text = 'tenant_7';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

    -- make sure that both tables created in tenant_7 are colocated
    SELECT COUNT(DISTINCT(colocationid)) = 1 FROM pg_dist_partition
    WHERE logicalrelid IN ('tenant_7.tbl_1'::regclass, 'tenant_7.tbl_2'::regclass);
 ?column?
---------------------------------------------------------------------
 t
(1 row)

COMMIT;
-- Test creating a tenant schema and a tenant table for it in the same transaction
-- but this time rollback the transaction.
BEGIN;
    CREATE SCHEMA tenant_8;
    CREATE TABLE tenant_8.tbl_1(a int, b text);
    CREATE TABLE tenant_8.tbl_2(a int, b text);
ROLLBACK;
SELECT COUNT(*)=0 FROM pg_dist_schema WHERE schemaid::regnamespace::text = 'tenant_8';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT COUNT(*)=0 FROM pg_dist_partition WHERE logicalrelid::text LIKE 'tenant_8.%';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

-- Verify that citus.enable_schema_based_sharding and citus.use_citus_managed_tables
-- GUC don't interfere with each other when creating a table in tenant schema.
--
-- In utility hook, we check whether the CREATE TABLE command is issued on a tenant
-- schema before checking whether citus.use_citus_managed_tables is set to ON to
-- avoid converting the table into a Citus managed table unnecessarily.
--
-- If the CREATE TABLE command is issued on a tenant schema, we skip the check
-- for citus.use_citus_managed_tables.
SET citus.use_citus_managed_tables TO ON;
CREATE TABLE tenant_7.tbl_3(a int, b text, PRIMARY KEY(a));
RESET citus.use_citus_managed_tables;
-- Verify that we don't unnecessarily convert a table into a Citus managed
-- table when creating it with a pre-defined foreign key to a reference table.
CREATE TABLE reference_table(a int PRIMARY KEY);
SELECT create_reference_table('reference_table');
 create_reference_table
---------------------------------------------------------------------

(1 row)

-- Notice that tenant_7.tbl_4 have foreign keys both to tenant_7.tbl_3 and
-- to reference_table.
CREATE TABLE tenant_7.tbl_4(a int REFERENCES reference_table, FOREIGN KEY(a) REFERENCES tenant_7.tbl_3(a) ON DELETE CASCADE);
INSERT INTO tenant_7.tbl_3 VALUES (1, 'a'), (2, 'b'), (3, 'c');
INSERT INTO reference_table VALUES (1), (2), (3);
INSERT INTO tenant_7.tbl_4 VALUES (1), (2), (3);
DELETE FROM tenant_7.tbl_3 WHERE a < 3;
SELECT * FROM tenant_7.tbl_4 ORDER BY a;
 a
---------------------------------------------------------------------
 3
(1 row)

SELECT COUNT(*)=2 FROM pg_dist_partition
WHERE logicalrelid IN ('tenant_7.tbl_3'::regclass, 'tenant_7.tbl_4'::regclass) AND
      partmethod = 'n' AND repmodel = 's' AND
      colocationid = (SELECT colocationid FROM pg_dist_partition WHERE logicalrelid = 'tenant_7.tbl_1'::regclass);
 ?column?
---------------------------------------------------------------------
 t
(1 row)

CREATE TABLE local_table(a int PRIMARY KEY);
-- fails because tenant tables cannot have foreign keys to local tables
CREATE TABLE tenant_7.tbl_5(a int REFERENCES local_table(a));
ERROR:  referenced table "local_table" must be a distributed table or a reference table
DETAIL:  To enforce foreign keys, the referencing and referenced rows need to be stored on the same node.
HINT:  You could use SELECT create_reference_table('local_table') to replicate the referenced table to all nodes or consider dropping the foreign key
-- Fails because tenant tables cannot have foreign keys to tenant tables
-- that belong to different tenant schemas.
CREATE TABLE tenant_5.tbl_5(a int, b text, FOREIGN KEY(a) REFERENCES tenant_7.tbl_3(a));
ERROR:  cannot create foreign key constraint since relations are not colocated or not referencing a reference table
DETAIL:  A distributed table can only have foreign keys if it is referencing another colocated hash distributed table or a reference table
CREATE SCHEMA tenant_9;
SELECT schemaid AS tenant_9_schemaid FROM pg_dist_schema WHERE schemaid::regnamespace::text = 'tenant_9' \gset
SELECT colocationid AS tenant_9_colocationid FROM pg_dist_schema WHERE schemaid::regnamespace::text = 'tenant_9' \gset
SELECT result FROM run_command_on_workers($$
    SELECT schemaid INTO tenant_9_schemaid FROM pg_dist_schema
    WHERE schemaid::regnamespace::text = 'tenant_9'
$$);
  result
---------------------------------------------------------------------
 SELECT 1
 SELECT 1
(2 rows)

DROP SCHEMA tenant_9;
-- (on coordinator) Make sure that dropping an empty tenant schema
-- doesn't leave any dangling entries in pg_dist_schema and
-- pg_dist_colocation.
SELECT COUNT(*)=0 FROM pg_dist_schema WHERE schemaid = :tenant_9_schemaid;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT COUNT(*)=0 FROM pg_dist_colocation WHERE colocationid = :tenant_9_colocationid;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

-- (on workers) Make sure that dropping an empty tenant schema
-- doesn't leave any dangling entries in pg_dist_schema and
-- pg_dist_colocation.
SELECT result FROM run_command_on_workers($$
    SELECT COUNT(*)=0 FROM pg_dist_schema
    WHERE schemaid = (SELECT schemaid FROM tenant_9_schemaid)
$$);
 result
---------------------------------------------------------------------
 t
 t
(2 rows)

SELECT format(
    'SELECT result FROM run_command_on_workers($$
        SELECT COUNT(*)=0 FROM pg_dist_colocation WHERE colocationid = %s;
    $$);',
:tenant_9_colocationid) AS verify_workers_query \gset
:verify_workers_query
 result
---------------------------------------------------------------------
 t
 t
(2 rows)

SELECT result FROM run_command_on_workers($$
    DROP TABLE tenant_9_schemaid
$$);
   result
---------------------------------------------------------------------
 DROP TABLE
 DROP TABLE
(2 rows)

CREATE TABLE tenant_3.search_path_test(a int);
INSERT INTO tenant_3.search_path_test VALUES (1), (10);
CREATE TABLE tenant_5.search_path_test(a int);
INSERT INTO tenant_5.search_path_test VALUES (2);
CREATE TABLE tenant_7.search_path_test(a int);
INSERT INTO tenant_7.search_path_test VALUES (3);
CREATE FUNCTION increment_one()
RETURNS void
LANGUAGE plpgsql
AS $$
BEGIN
    UPDATE search_path_test SET a = a + 1;
END;
$$;
CREATE FUNCTION decrement_one()
RETURNS void
LANGUAGE plpgsql
AS $$
BEGIN
    UPDATE search_path_test SET a = a - 1;
END;
$$;
SET search_path TO tenant_5;
PREPARE list_tuples AS SELECT * FROM search_path_test ORDER BY a;
SELECT * FROM search_path_test ORDER BY a;
 a
---------------------------------------------------------------------
 2
(1 row)

SET search_path TO tenant_3;
DELETE FROM search_path_test WHERE a = 1;
SELECT * FROM search_path_test ORDER BY a;
 a
---------------------------------------------------------------------
 10
(1 row)

SELECT regular_schema.increment_one();
 increment_one
---------------------------------------------------------------------

(1 row)

EXECUTE list_tuples;
 a
---------------------------------------------------------------------
 11
(1 row)

SET search_path TO tenant_7;
DROP TABLE search_path_test;
SELECT * FROM pg_dist_partition WHERE logicalrelid::text = 'search_path_test';
 logicalrelid | partmethod | partkey | colocationid | repmodel | autoconverted
---------------------------------------------------------------------
(0 rows)

SET search_path TO tenant_5;
SELECT regular_schema.decrement_one();
 decrement_one
---------------------------------------------------------------------

(1 row)

EXECUTE list_tuples;
 a
---------------------------------------------------------------------
 1
(1 row)

SET search_path TO regular_schema;
CREATE USER test_other_super_user WITH superuser;
\c - test_other_super_user
SET citus.enable_schema_based_sharding TO ON;
CREATE SCHEMA tenant_9;
\c - postgres
SET search_path TO regular_schema;
SET citus.next_shard_id TO 1930000;
SET citus.shard_count TO 32;
SET citus.shard_replication_factor TO 1;
SET client_min_messages TO NOTICE;
SET citus.enable_schema_based_sharding TO ON;
SELECT schemaid AS tenant_9_schemaid FROM pg_dist_schema WHERE schemaid::regnamespace::text = 'tenant_9' \gset
SELECT colocationid AS tenant_9_colocationid FROM pg_dist_schema WHERE schemaid::regnamespace::text = 'tenant_9' \gset
SELECT result FROM run_command_on_workers($$
    SELECT schemaid INTO tenant_9_schemaid FROM pg_dist_schema
    WHERE schemaid::regnamespace::text = 'tenant_9'
$$);
  result
---------------------------------------------------------------------
 SELECT 1
 SELECT 1
(2 rows)

DROP OWNED BY test_other_super_user;
-- (on coordinator) Make sure that dropping an empty tenant schema
-- (via DROP OWNED BY) doesn't leave any dangling entries in
-- pg_dist_schema and pg_dist_colocation.
SELECT COUNT(*)=0 FROM pg_dist_schema WHERE schemaid = :tenant_9_schemaid;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT COUNT(*)=0 FROM pg_dist_colocation WHERE colocationid = :tenant_9_colocationid;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

-- (on workers) Make sure that dropping an empty tenant schema
-- (via DROP OWNED BY) doesn't leave any dangling entries in
-- pg_dist_schema and pg_dist_colocation.
SELECT result FROM run_command_on_workers($$
    SELECT COUNT(*)=0 FROM pg_dist_schema
    WHERE schemaid = (SELECT schemaid FROM tenant_9_schemaid)
$$);
 result
---------------------------------------------------------------------
 t
 t
(2 rows)

SELECT format(
    'SELECT result FROM run_command_on_workers($$
        SELECT COUNT(*)=0 FROM pg_dist_colocation WHERE colocationid = %s;
    $$);',
:tenant_9_colocationid) AS verify_workers_query \gset
:verify_workers_query
 result
---------------------------------------------------------------------
 t
 t
(2 rows)

SELECT result FROM run_command_on_workers($$
    DROP TABLE tenant_9_schemaid
$$);
   result
---------------------------------------------------------------------
 DROP TABLE
 DROP TABLE
(2 rows)

DROP USER test_other_super_user;
CREATE ROLE test_non_super_user WITH LOGIN;
ALTER ROLE test_non_super_user NOSUPERUSER;
GRANT CREATE ON DATABASE regression TO test_non_super_user;
GRANT CREATE ON SCHEMA public TO test_non_super_user ;
\c - test_non_super_user
SET search_path TO regular_schema;
SET citus.next_shard_id TO 1940000;
SET citus.shard_count TO 32;
SET citus.shard_replication_factor TO 1;
SET client_min_messages TO NOTICE;
SET citus.enable_schema_based_sharding TO ON;
-- test create / drop tenant schema / table
CREATE SCHEMA tenant_10;
CREATE TABLE tenant_10.tbl_1(a int, b text);
CREATE TABLE tenant_10.tbl_2(a int, b text);
DROP TABLE tenant_10.tbl_2;
CREATE SCHEMA tenant_11;
SELECT schemaid AS tenant_10_schemaid FROM pg_dist_schema WHERE schemaid::regnamespace::text = 'tenant_10' \gset
SELECT colocationid AS tenant_10_colocationid FROM pg_dist_schema WHERE schemaid::regnamespace::text = 'tenant_10' \gset
SELECT schemaid AS tenant_11_schemaid FROM pg_dist_schema WHERE schemaid::regnamespace::text = 'tenant_11' \gset
SELECT colocationid AS tenant_11_colocationid FROM pg_dist_schema WHERE schemaid::regnamespace::text = 'tenant_11' \gset
SELECT result FROM run_command_on_workers($$
    SELECT schemaid INTO tenant_10_schemaid FROM pg_dist_schema
    WHERE schemaid::regnamespace::text = 'tenant_10'
$$);
  result
---------------------------------------------------------------------
 SELECT 1
 SELECT 1
(2 rows)

SELECT result FROM run_command_on_workers($$
    SELECT schemaid INTO tenant_11_schemaid FROM pg_dist_schema
    WHERE schemaid::regnamespace::text = 'tenant_11'
$$);
  result
---------------------------------------------------------------------
 SELECT 1
 SELECT 1
(2 rows)

-- (on coordinator) Verify metadata for tenant schemas that are created via non-super-user.
SELECT COUNT(DISTINCT(schemaid))=2 FROM pg_dist_schema WHERE schemaid IN (:tenant_10_schemaid, :tenant_11_schemaid);
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT COUNT(DISTINCT(colocationid))=2 FROM pg_dist_colocation WHERE colocationid IN (:tenant_10_colocationid, :tenant_11_colocationid);
 ?column?
---------------------------------------------------------------------
 t
(1 row)

-- (on workers) Verify metadata for tenant schemas that are created via non-super-user.
SELECT result FROM run_command_on_workers($$
    SELECT COUNT(DISTINCT(schemaid))=2 FROM pg_dist_schema
    WHERE schemaid IN (SELECT schemaid FROM tenant_10_schemaid UNION SELECT schemaid FROM tenant_11_schemaid)
$$);
 result
---------------------------------------------------------------------
 t
 t
(2 rows)

SELECT format(
    'SELECT result FROM run_command_on_workers($$
        SELECT COUNT(DISTINCT(colocationid))=2 FROM pg_dist_colocation WHERE colocationid IN (%s, %s);
    $$);',
:tenant_10_colocationid, :tenant_11_colocationid) AS verify_workers_query \gset
:verify_workers_query
 result
---------------------------------------------------------------------
 t
 t
(2 rows)

SET client_min_messages TO WARNING;
DROP SCHEMA tenant_10, tenant_11 CASCADE;
SET client_min_messages TO NOTICE;
-- (on coordinator) Verify that dropping a tenant schema via non-super-user
-- deletes the associated pg_dist_schema entry.
SELECT COUNT(*)=0 FROM pg_dist_schema WHERE schemaid IN (:tenant_10_schemaid, :tenant_11_schemaid);
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT COUNT(*)=0 FROM pg_dist_colocation WHERE colocationid IN (:tenant_10_colocationid, :tenant_11_colocationid);
 ?column?
---------------------------------------------------------------------
 t
(1 row)

-- (on workers) Verify that dropping a tenant schema via non-super-user
-- deletes the associated pg_dist_schema entry.
SELECT result FROM run_command_on_workers($$
    SELECT COUNT(*)=0 FROM pg_dist_schema
    WHERE schemaid IN (SELECT schemaid FROM tenant_10_schemaid UNION SELECT schemaid FROM tenant_11_schemaid)
$$);
 result
---------------------------------------------------------------------
 t
 t
(2 rows)

SELECT format(
    'SELECT result FROM run_command_on_workers($$
        SELECT COUNT(*)=0 FROM pg_dist_colocation WHERE colocationid IN (%s, %s);
    $$);',
:tenant_10_colocationid, :tenant_11_colocationid) AS verify_workers_query \gset
:verify_workers_query
 result
---------------------------------------------------------------------
 t
 t
(2 rows)

SELECT result FROM run_command_on_workers($$
    DROP TABLE tenant_10_schemaid
$$);
   result
---------------------------------------------------------------------
 DROP TABLE
 DROP TABLE
(2 rows)

SELECT result FROM run_command_on_workers($$
    DROP TABLE tenant_11_schemaid
$$);
   result
---------------------------------------------------------------------
 DROP TABLE
 DROP TABLE
(2 rows)

\c - postgres
REVOKE CREATE ON DATABASE regression FROM test_non_super_user;
REVOKE CREATE ON SCHEMA public FROM test_non_super_user;
DROP ROLE test_non_super_user;
\c - - - :worker_1_port
-- test creating a tenant table from workers
CREATE TABLE tenant_3.tbl_1(a int, b text);
ERROR:  cannot create tables in a distributed schema from a worker node
HINT:  Connect to the coordinator node and try again.
-- test creating a tenant schema from workers
SET citus.enable_schema_based_sharding TO ON;
CREATE SCHEMA worker_tenant_schema;
ERROR:  operation is not allowed on this node
HINT:  Connect to the coordinator and run it again.
SET citus.enable_schema_based_sharding TO OFF;
-- Enable the GUC on workers to make sure that the CREATE SCHEMA/ TABLE
-- commands that we send to workers don't recursively try creating a
-- tenant schema / table.
ALTER SYSTEM SET citus.enable_schema_based_sharding TO ON;
SELECT pg_reload_conf();
 pg_reload_conf
---------------------------------------------------------------------
 t
(1 row)

\c - - - :worker_2_port
ALTER SYSTEM SET citus.enable_schema_based_sharding TO ON;
SELECT pg_reload_conf();
 pg_reload_conf
---------------------------------------------------------------------
 t
(1 row)

-- Verify that citus_internal.unregister_tenant_schema_globally is a no-op
-- on workers.
SELECT citus_internal.unregister_tenant_schema_globally('tenant_3'::regnamespace, 'tenant_3');
 unregister_tenant_schema_globally
---------------------------------------------------------------------

(1 row)

\c - - - :master_port
SET search_path TO regular_schema;
SET citus.next_shard_id TO 1950000;
SET citus.shard_count TO 32;
SET citus.shard_replication_factor TO 1;
SET client_min_messages TO NOTICE;
CREATE TABLE tenant_3.tbl_1(a int, b text);
SET citus.enable_schema_based_sharding TO ON;
CREATE SCHEMA tenant_6;
CREATE TABLE tenant_6.tbl_1(a int, b text);
-- verify pg_dist_partition entries for tenant_3.tbl_1 and tenant_6.tbl_1
SELECT COUNT(*)=2 FROM pg_dist_partition
WHERE logicalrelid IN ('tenant_3.tbl_1'::regclass, 'tenant_6.tbl_1'::regclass) AND
      partmethod = 'n' AND repmodel = 's' AND colocationid > 0;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

\c - - - :worker_1_port
ALTER SYSTEM RESET citus.enable_schema_based_sharding;
SELECT pg_reload_conf();
 pg_reload_conf
---------------------------------------------------------------------
 t
(1 row)

\c - - - :worker_2_port
ALTER SYSTEM RESET citus.enable_schema_based_sharding;
SELECT pg_reload_conf();
 pg_reload_conf
---------------------------------------------------------------------
 t
(1 row)

\c - - - :master_port
SET search_path TO regular_schema;
CREATE TABLE type_sing(a INT);
-- errors out because shard_replication_factor = 2
SELECT create_distributed_table('type_sing', NULL, colocate_with:='none');
ERROR:  could not create single shard table: citus.shard_replication_factor is greater than 1
HINT:  Consider setting citus.shard_replication_factor to 1 and try again
SET citus.shard_replication_factor TO 1;
SELECT create_distributed_table('type_sing', NULL, colocate_with:='none');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

SET citus.enable_schema_based_sharding TO ON;
CREATE SCHEMA type_sch;
CREATE TABLE type_sch.tbl (a INT);
SELECT table_name, citus_table_type FROM public.citus_tables WHERE table_name::text LIKE 'type_%';
  table_name  | citus_table_type
---------------------------------------------------------------------
 type_sch.tbl | schema
 type_sing    | distributed
(2 rows)

SELECT table_name, citus_table_type FROM citus_shards WHERE table_name::text LIKE 'type_%' AND nodeport IN (:worker_1_port, :worker_2_port);
  table_name  | citus_table_type
---------------------------------------------------------------------
 type_sch.tbl | schema
 type_sing    | distributed
(2 rows)

RESET citus.enable_schema_based_sharding;
-- test citus_schemas
SET citus.enable_schema_based_sharding TO ON;
CREATE USER citus_schema_role SUPERUSER;
SET ROLE citus_schema_role;
CREATE SCHEMA citus_sch1;
CREATE TABLE citus_sch1.tbl1(a INT);
CREATE TABLE citus_sch1.tbl2(a INT);
RESET ROLE;
CREATE SCHEMA citus_sch2;
CREATE TABLE citus_sch2.tbl1(a INT);
SET citus.enable_schema_based_sharding TO OFF;
INSERT INTO citus_sch1.tbl1 SELECT * FROM generate_series(1, 10000);
INSERT INTO citus_sch1.tbl2 SELECT * FROM generate_series(1, 5000);
INSERT INTO citus_sch2.tbl1 SELECT * FROM generate_series(1, 12000);
SELECT
    cs.schema_name,
    cs.colocation_id = ctc.colocation_id AS correct_colocation_id,
    cs.schema_size = ctc.calculated_size AS correct_size,
    cs.schema_owner
FROM public.citus_schemas cs
JOIN
(
    SELECT
        c.relnamespace, ct.colocation_id,
        pg_size_pretty(sum(citus_total_relation_size(ct.table_name))) AS calculated_size
    FROM public.citus_tables ct, pg_class c
    WHERE ct.table_name::oid = c.oid
    GROUP BY 1, 2
) ctc ON cs.schema_name = ctc.relnamespace
WHERE cs.schema_name::text LIKE 'citus\_sch_'
ORDER BY cs.schema_name::text;
 schema_name | correct_colocation_id | correct_size |   schema_owner
---------------------------------------------------------------------
 citus_sch1  | t                     | t            | citus_schema_role
 citus_sch2  | t                     | t            | postgres
(2 rows)

-- test empty schema and empty tables
SET citus.enable_schema_based_sharding TO ON;
CREATE SCHEMA citus_empty_sch1;
CREATE SCHEMA citus_empty_sch2;
CREATE TABLE citus_empty_sch2.tbl1(a INT);
SET citus.enable_schema_based_sharding TO OFF;
SELECT schema_name, schema_size FROM public.citus_schemas
WHERE schema_name::text LIKE 'citus\_empty\_sch_' ORDER BY schema_name::text;
   schema_name    | schema_size
---------------------------------------------------------------------
 citus_empty_sch1 | 0 bytes
 citus_empty_sch2 | 0 bytes
(2 rows)

-- test with non-privileged role
CREATE USER citus_schema_nonpri;
SET ROLE citus_schema_nonpri;
SET client_min_messages TO ERROR;
SELECT schema_name, colocation_id > 0 AS colocation_id_visible, schema_size IS NOT NULL AS schema_size_visible, schema_owner
FROM public.citus_schemas WHERE schema_name::text LIKE 'citus\_sch_' ORDER BY schema_name::text;
 schema_name | colocation_id_visible | schema_size_visible |   schema_owner
---------------------------------------------------------------------
 citus_sch1  | t                     | f                   | citus_schema_role
 citus_sch2  | t                     | f                   | postgres
(2 rows)

RESET client_min_messages;
RESET ROLE;
-- test using citus_tables from workers
\c - - - :worker_1_port
SELECT schema_name, colocation_id > 0 AS colocation_id_visible, schema_size IS NOT NULL AS schema_size_visible, schema_owner
FROM public.citus_schemas WHERE schema_name::text LIKE 'citus\_sch_' ORDER BY schema_name::text;
 schema_name | colocation_id_visible | schema_size_visible |   schema_owner
---------------------------------------------------------------------
 citus_sch1  | t                     | t                   | citus_schema_role
 citus_sch2  | t                     | t                   | postgres
(2 rows)

\c - - - :master_port
SET search_path TO regular_schema;
-- test we handle create schema with authorization properly for distributed schema
SET citus.enable_schema_based_sharding TO ON;
CREATE ROLE authschema;
CREATE SCHEMA AUTHORIZATION authschema;
SET citus.enable_schema_based_sharding TO OFF;
SELECT result FROM run_command_on_all_nodes($$
    SELECT COUNT(*)=1
     FROM pg_dist_schema
    WHERE schemaid::regnamespace::text = 'authschema';
$$);
 result
---------------------------------------------------------------------
 t
 t
 t
(3 rows)

-- mat view can be created under tenant schema
SET citus.enable_schema_based_sharding TO ON;
SET citus.shard_replication_factor TO 1;
CREATE SCHEMA sc1;
CREATE TABLE sc1.t1 (a int);
CREATE MATERIALIZED VIEW sc1.v1 AS SELECT * FROM sc1.t1;
SET citus.enable_schema_based_sharding TO OFF;
-- on coordinator, verify that schema is distributed
SELECT colocationid > 0 FROM pg_dist_schema
WHERE schemaid::regnamespace::text = 'sc1';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

-- on workers, verify that schema is distributed
SELECT result FROM run_command_on_workers($$
    SELECT array_agg(colocationid > 0) FROM pg_dist_schema
    WHERE schemaid::regnamespace::text = 'sc1'
$$);
 result
---------------------------------------------------------------------
 {t}
 {t}
(2 rows)

SET client_min_messages TO WARNING;
DROP SCHEMA regular_schema, tenant_3, tenant_5, tenant_7, tenant_6, type_sch, citus_sch1, citus_sch2, citus_empty_sch1, citus_empty_sch2, authschema, sc1 CASCADE;
DROP ROLE citus_schema_role, citus_schema_nonpri, authschema;
SELECT citus_remove_node('localhost', :master_port);
 citus_remove_node
---------------------------------------------------------------------

(1 row)

