diff --git a/src/backend/distributed/executor/multi_utility.c b/src/backend/distributed/executor/multi_utility.c index fc21ddf20..3947dced2 100644 --- a/src/backend/distributed/executor/multi_utility.c +++ b/src/backend/distributed/executor/multi_utility.c @@ -42,6 +42,7 @@ #include "distributed/metadata_sync.h" #include "distributed/multi_copy.h" #include "distributed/multi_join_order.h" +#include "distributed/multi_partitioning_utils.h" #include "distributed/multi_planner.h" #include "distributed/multi_router_executor.h" #include "distributed/multi_router_planner.h" @@ -545,6 +546,45 @@ multi_ProcessUtility(PlannedStmt *pstmt, } } } + else if (IsA(parsetree, AlterTableStmt)) + { + AlterTableStmt *alterTableStatement = (AlterTableStmt *) parsetree; + List *commandList = alterTableStatement->cmds; + ListCell *commandCell = NULL; + + foreach(commandCell, commandList) + { + AlterTableCmd *alterTableCommand = (AlterTableCmd *) lfirst(commandCell); + + AlterTableType alterTableType = alterTableCommand->subtype; + + if (alterTableType == AT_AttachPartition) + { + PartitionCmd *partitionCommand = (PartitionCmd *) alterTableCommand->def; + + char *relationName = partitionCommand->name->relname; + char *schemaName = partitionCommand->name->schemaname ? + partitionCommand->name->schemaname : "public"; + + Oid relationId = get_relname_relid(relationName, + get_namespace_oid(schemaName, false)); + Oid parentId = PartitionParentOid(relationId); + + if (IsDistributedTable(parentId)) + { + Var *parentPartitionKey = DistPartitionKey(parentId); + char *parentPartitionKeyStr = + get_relid_attribute_name(parentId, + parentPartitionKey->varattno); + + CreateHashDistributedTable(relationId, parentPartitionKeyStr, + get_rel_name(parentId), 0, 0); + } + } + } + } + + #endif /* TODO: fold VACUUM's processing into the above block */ @@ -1070,6 +1110,30 @@ PlanAlterTableStmt(AlterTableStmt *alterTableStatement, const char *alterTableCo constraint->skip_validation = true; } } +#if (PG_VERSION_NUM >= 100000) + else if (alterTableType == AT_AttachPartition) + { + PartitionCmd *partitionCommand = (PartitionCmd *) command->def; + + char *relationName = partitionCommand->name->relname; + char *schemaName = partitionCommand->name->schemaname ? + partitionCommand->name->schemaname : "public"; + + Oid relationId = get_relname_relid(relationName, + get_namespace_oid(schemaName, false)); + Oid parentId = leftRelationId; + + /* + * Do not generate tasks if relation is not distributed and the parent + * is distributed. Because, we'll manually convert the relation into + * distribtued relation and co-locate with its parent. + */ + if (!IsDistributedTable(relationId) && IsDistributedTable(parentId)) + { + return NIL; + } + } +#endif } ddlJob = palloc0(sizeof(DDLJob)); @@ -1813,6 +1877,9 @@ ErrorIfUnsupportedAlterTableStmt(AlterTableStmt *alterTableStatement) case AT_DropConstraint: case AT_EnableTrigAll: case AT_DisableTrigAll: +#if (PG_VERSION_NUM >= 100000) + case AT_AttachPartition: +#endif { /* * We will not perform any special check for ALTER TABLE DROP CONSTRAINT diff --git a/src/test/regress/expected/multi_partitioning.out b/src/test/regress/expected/multi_partitioning.out index b8da66b37..b73e06d7e 100644 --- a/src/test/regress/expected/multi_partitioning.out +++ b/src/test/regress/expected/multi_partitioning.out @@ -130,6 +130,59 @@ ORDER BY localhost | 57638 | 8 (2 rows) +-- citus can also support ALTER TABLE .. ATTACH PARTITION +-- even if the partition is not distributed +CREATE TABLE partitioning_test_2012(id int, time date); +ALTER TABLE partitioning_test ATTACH PARTITION partitioning_test_2012 FOR VALUES FROM ('2012-01-01') TO ('2013-01-01'); +SELECT + * +FROM + pg_dist_partition +WHERE + logicalrelid IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010', 'partitioning_test_2011', 'partitioning_test_2012') +ORDER BY 1; + logicalrelid | partmethod | partkey | colocationid | repmodel +------------------------+------------+------------------------------------------------------------------------------------------------------------------------+--------------+---------- + partitioning_test | h | {VAR :varno 1 :varattno 1 :vartype 23 :vartypmod -1 :varcollid 0 :varlevelsup 0 :varnoold 1 :varoattno 1 :location -1} | 2 | c + partitioning_test_2009 | h | {VAR :varno 1 :varattno 1 :vartype 23 :vartypmod -1 :varcollid 0 :varlevelsup 0 :varnoold 1 :varoattno 1 :location -1} | 2 | c + partitioning_test_2010 | h | {VAR :varno 1 :varattno 1 :vartype 23 :vartypmod -1 :varcollid 0 :varlevelsup 0 :varnoold 1 :varoattno 1 :location -1} | 2 | c + partitioning_test_2011 | h | {VAR :varno 1 :varattno 1 :vartype 23 :vartypmod -1 :varcollid 0 :varlevelsup 0 :varnoold 1 :varoattno 1 :location -1} | 2 | c + partitioning_test_2012 | h | {VAR :varno 1 :varattno 1 :vartype 23 :vartypmod -1 :varcollid 0 :varlevelsup 0 :varnoold 1 :varoattno 1 :location -1} | 2 | c +(5 rows) + +SELECT + logicalrelid, count(*) +FROM pg_dist_shard + WHERE logicalrelid IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010', 'partitioning_test_2011', 'partitioning_test_2012') +GROUP BY + logicalrelid +ORDER BY + 1,2; + logicalrelid | count +------------------------+------- + partitioning_test | 4 + partitioning_test_2009 | 4 + partitioning_test_2010 | 4 + partitioning_test_2011 | 4 + partitioning_test_2012 | 4 +(5 rows) + +SELECT + nodename, nodeport, count(*) +FROM + pg_dist_shard_placement +WHERE + shardid IN (SELECT shardid FROM pg_dist_shard WHERE logicalrelid IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010', 'partitioning_test_2011', 'partitioning_test_2012') ) +GROUP BY + nodename, nodeport +ORDER BY + 1,2,3; + nodename | nodeport | count +-----------+----------+------- + localhost | 57637 | 10 + localhost | 57638 | 10 +(2 rows) + -- dropping the parent should CASCADE to the children as well DROP TABLE partitioning_test; \d+ partitioning_test* diff --git a/src/test/regress/expected/multi_partitioning_0.out b/src/test/regress/expected/multi_partitioning_0.out index f95f9978b..4bd3cf35c 100644 --- a/src/test/regress/expected/multi_partitioning_0.out +++ b/src/test/regress/expected/multi_partitioning_0.out @@ -119,9 +119,56 @@ GROUP BY ORDER BY 1,2,3; ERROR: relation "partitioning_test" does not exist +LINE 6: ...shardid FROM pg_dist_shard WHERE logicalrelid IN ('partition... + ^ +-- citus can also support ALTER TABLE .. ATTACH PARTITION +-- even if the partition is not distributed +CREATE TABLE partitioning_test_2012(id int, time date); +ALTER TABLE partitioning_test ATTACH PARTITION partitioning_test_2012 FOR VALUES FROM ('2012-01-01') TO ('2013-01-01'); +ERROR: syntax error at or near "ATTACH" +LINE 1: ALTER TABLE partitioning_test ATTACH PARTITION partitioning_... + ^ +SELECT + * +FROM + pg_dist_partition +WHERE + logicalrelid IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010', 'partitioning_test_2011', 'partitioning_test_2012') +ORDER BY 1; +ERROR: relation "partitioning_test" does not exist +LINE 6: logicalrelid IN ('partitioning_test', 'partitioning_test_20... + ^ +SELECT + logicalrelid, count(*) +FROM pg_dist_shard + WHERE logicalrelid IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010', 'partitioning_test_2011', 'partitioning_test_2012') +GROUP BY + logicalrelid +ORDER BY + 1,2; +ERROR: relation "partitioning_test" does not exist +LINE 4: WHERE logicalrelid IN ('partitioning_test', 'partitioning_t... + ^ +SELECT + nodename, nodeport, count(*) +FROM + pg_dist_shard_placement +WHERE + shardid IN (SELECT shardid FROM pg_dist_shard WHERE logicalrelid IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010', 'partitioning_test_2011', 'partitioning_test_2012') ) +GROUP BY + nodename, nodeport +ORDER BY + 1,2,3; +ERROR: relation "partitioning_test" does not exist LINE 6: ...shardid FROM pg_dist_shard WHERE logicalrelid IN ('partition... ^ -- dropping the parent should CASCADE to the children as well DROP TABLE partitioning_test; ERROR: table "partitioning_test" does not exist \d+ partitioning_test* + Table "public.partitioning_test_2012" + Column | Type | Modifiers | Storage | Stats target | Description +--------+---------+-----------+---------+--------------+------------- + id | integer | | plain | | + time | date | | plain | | + diff --git a/src/test/regress/sql/multi_partitioning.sql b/src/test/regress/sql/multi_partitioning.sql index 3b1fd5b82..c5495d497 100644 --- a/src/test/regress/sql/multi_partitioning.sql +++ b/src/test/regress/sql/multi_partitioning.sql @@ -85,6 +85,41 @@ GROUP BY ORDER BY 1,2,3; + +-- citus can also support ALTER TABLE .. ATTACH PARTITION +-- even if the partition is not distributed +CREATE TABLE partitioning_test_2012(id int, time date); +ALTER TABLE partitioning_test ATTACH PARTITION partitioning_test_2012 FOR VALUES FROM ('2012-01-01') TO ('2013-01-01'); + +SELECT + * +FROM + pg_dist_partition +WHERE + logicalrelid IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010', 'partitioning_test_2011', 'partitioning_test_2012') +ORDER BY 1; + +SELECT + logicalrelid, count(*) +FROM pg_dist_shard + WHERE logicalrelid IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010', 'partitioning_test_2011', 'partitioning_test_2012') +GROUP BY + logicalrelid +ORDER BY + 1,2; + +SELECT + nodename, nodeport, count(*) +FROM + pg_dist_shard_placement +WHERE + shardid IN (SELECT shardid FROM pg_dist_shard WHERE logicalrelid IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010', 'partitioning_test_2011', 'partitioning_test_2012') ) +GROUP BY + nodename, nodeport +ORDER BY + 1,2,3; + + -- dropping the parent should CASCADE to the children as well DROP TABLE partitioning_test;