From 7b0bc62173d73ce3a5c651bc80cbe279efe99372 Mon Sep 17 00:00:00 2001 From: Ahmet Gedemenli Date: Tue, 13 Jun 2023 17:54:09 +0300 Subject: [PATCH] Support CREATE TABLE .. AS SELECT .. commands for tenant tables (#6998) Support CREATE TABLE .. AS SELECT .. commands for tenant tables --- src/backend/distributed/commands/table.c | 11 ++-- .../expected/schema_based_sharding.out | 55 ++++++++++++++++--- .../regress/sql/schema_based_sharding.sql | 22 ++++++-- 3 files changed, 70 insertions(+), 18 deletions(-) diff --git a/src/backend/distributed/commands/table.c b/src/backend/distributed/commands/table.c index aa4570f5e..4a1e69e14 100644 --- a/src/backend/distributed/commands/table.c +++ b/src/backend/distributed/commands/table.c @@ -4130,10 +4130,13 @@ ConvertNewTableIfNecessary(Node *createStmt) if (ShouldCreateTenantSchemaTable(createdRelationId)) { - ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot create a tenant table using " - "CREATE TABLE AS or SELECT INTO " - "statements"))); + /* not try to convert the table if it already exists and IF NOT EXISTS syntax is used */ + if (createTableAsStmt->if_not_exists && IsCitusTable(createdRelationId)) + { + return; + } + + CreateTenantSchemaTable(createdRelationId); } /* diff --git a/src/test/regress/expected/schema_based_sharding.out b/src/test/regress/expected/schema_based_sharding.out index 1bc5d7963..06d759e1f 100644 --- a/src/test/regress/expected/schema_based_sharding.out +++ b/src/test/regress/expected/schema_based_sharding.out @@ -384,13 +384,36 @@ SELECT EXISTS( t (1 row) --- verify that we don't allow creating tenant tables by using CREATE TABLE AS / SELECT INTO commands +-- 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; -ERROR: cannot create a tenant table using CREATE TABLE AS or SELECT INTO statements -CREATE TABLE IF NOT EXISTS tenant_4.tbl_3 AS SELECT 1 as a, 'text' as b; -ERROR: cannot create a tenant table using CREATE TABLE AS or SELECT INTO statements -SELECT 1 as a, 'text' as b INTO tenant_4.tbl_3; -ERROR: cannot create a tenant table using CREATE TABLE AS or SELECT INTO statements +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 ( @@ -399,9 +422,23 @@ CREATE TABLE tenant_4.employees OF employee_type ( ); ERROR: cannot create a tenant table by using CREATE TABLE OF syntax -- verify that we act accordingly when if not exists is used -CREATE TABLE IF NOT EXISTS tenant_4.tbl_3(a int, b text); -CREATE TABLE IF NOT EXISTS tenant_4.tbl_3(a int, b text); -NOTICE: relation "tbl_3" already exists, skipping +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'); diff --git a/src/test/regress/sql/schema_based_sharding.sql b/src/test/regress/sql/schema_based_sharding.sql index 4dda95dcd..ad20757ee 100644 --- a/src/test/regress/sql/schema_based_sharding.sql +++ b/src/test/regress/sql/schema_based_sharding.sql @@ -273,10 +273,17 @@ SELECT EXISTS( inhparent = 'tenant_4.parent_attach_test'::regclass ) AS is_partition; --- verify that we don't allow creating tenant tables by using CREATE TABLE AS / SELECT INTO commands +-- 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; -CREATE TABLE IF NOT EXISTS tenant_4.tbl_3 AS SELECT 1 as a, 'text' as b; -SELECT 1 as a, 'text' as b INTO tenant_4.tbl_3; +CREATE TEMP TABLE IF NOT EXISTS tenant_4.tbl_4 AS SELECT 1 as a, 'text' as b; +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; +SELECT 1 as a, 'text' as b INTO tenant_4.tbl_5; + +-- verify we can query the newly created tenant tables +SELECT * FROM tenant_4.tbl_3; +SELECT COUNT(*) FROM tenant_4.tbl_5; CREATE TYPE employee_type AS (name text, salary numeric); @@ -287,8 +294,13 @@ CREATE TABLE tenant_4.employees OF employee_type ( ); -- verify that we act accordingly when if not exists is used -CREATE TABLE IF NOT EXISTS tenant_4.tbl_3(a int, b text); -CREATE TABLE IF NOT EXISTS tenant_4.tbl_3(a int, b text); +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); + +SELECT logicalrelid, partmethod + FROM pg_dist_partition + WHERE logicalrelid::text LIKE 'tenant_4.tbl%' + ORDER BY logicalrelid; CREATE TABLE regular_schema.local(a int, b text);