diff options
-rw-r--r-- | doc/src/sgml/ref/alter_table.sgml | 2 | ||||
-rw-r--r-- | doc/src/sgml/ref/create_foreign_table.sgml | 4 | ||||
-rw-r--r-- | src/backend/commands/indexcmds.c | 20 | ||||
-rw-r--r-- | src/backend/commands/tablecmds.c | 45 | ||||
-rw-r--r-- | src/backend/tcop/utility.c | 12 | ||||
-rw-r--r-- | src/test/regress/expected/foreign_data.out | 56 | ||||
-rw-r--r-- | src/test/regress/sql/foreign_data.sql | 42 |
7 files changed, 172 insertions, 9 deletions
diff --git a/doc/src/sgml/ref/alter_table.sgml b/doc/src/sgml/ref/alter_table.sgml index 51b5bf91d8e..f362a676c69 100644 --- a/doc/src/sgml/ref/alter_table.sgml +++ b/doc/src/sgml/ref/alter_table.sgml @@ -861,7 +861,7 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM as if <command>ALTER INDEX ATTACH PARTITION</command> had been executed. Note that if the existing table is a foreign table, it is currently not allowed to attach the table as a partition of the target table if there - are indexes on the target table. (See also + are <literal>UNIQUE</literal> indexes on the target table. (See also <xref linkend="sql-createforeigntable"/>.) </para> diff --git a/doc/src/sgml/ref/create_foreign_table.sgml b/doc/src/sgml/ref/create_foreign_table.sgml index 53f86f96f9c..f32c36b4e1a 100644 --- a/doc/src/sgml/ref/create_foreign_table.sgml +++ b/doc/src/sgml/ref/create_foreign_table.sgml @@ -169,8 +169,8 @@ CHECK ( <replaceable class="parameter">expression</replaceable> ) [ NO INHERIT ] See the similar form of <xref linkend="sql-createtable"/> for more details. Note that it is currently not allowed to create the foreign table as a - partition of the parent table if there are indexes on the parent table. - (See also + partition of the parent table if there are <literal>UNIQUE</literal> + indexes on the parent table. (See also <link linkend="sql-altertable"><command>ALTER TABLE ATTACH PARTITION</command></link>.) </para> </listitem> diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index f00291da1b6..11370c65906 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -922,6 +922,26 @@ DefineIndex(Oid relationId, int maplen; childrel = heap_open(childRelid, lockmode); + + /* + * Don't try to create indexes on foreign tables, though. + * Skip those if a regular index, or fail if trying to create + * a constraint index. + */ + if (childrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE) + { + if (stmt->unique || stmt->primary) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot create unique index on partitioned table \"%s\"", + RelationGetRelationName(rel)), + errdetail("Table \"%s\" contains partitions that are foreign tables.", + RelationGetRelationName(rel)))); + + heap_close(childrel, lockmode); + continue; + } + childidxs = RelationGetIndexList(childrel); attmap = convert_tuples_by_name_map(RelationGetDescr(childrel), diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index b6f6bca26b8..b60e25a0fc3 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -939,6 +939,22 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, IndexStmt *idxstmt; Oid constraintOid; + if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE) + { + if (idxRel->rd_index->indisunique) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot create foreign partition of partitioned table \"%s\"", + RelationGetRelationName(parent)), + errdetail("Table \"%s\" contains indexes that are unique.", + RelationGetRelationName(parent)))); + else + { + index_close(idxRel, AccessShareLock); + continue; + } + } + attmap = convert_tuples_by_name_map(RelationGetDescr(rel), RelationGetDescr(parent), gettext_noop("could not convert row type")); @@ -15014,6 +15030,34 @@ AttachPartitionEnsureIndexes(Relation rel, Relation attachrel) } /* + * If we're attaching a foreign table, we must fail if any of the indexes + * is a constraint index; otherwise, there's nothing to do here. Do this + * before starting work, to avoid wasting the effort of building a few + * non-unique indexes before coming across a unique one. + */ + if (attachrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE) + { + foreach(cell, idxes) + { + Oid idx = lfirst_oid(cell); + Relation idxRel = index_open(idx, AccessShareLock); + + if (idxRel->rd_index->indisunique || + idxRel->rd_index->indisprimary) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot attach foreign table \"%s\" as partition of partitioned table \"%s\"", + RelationGetRelationName(attachrel), + RelationGetRelationName(rel)), + errdetail("Table \"%s\" contains unique indexes.", + RelationGetRelationName(rel)))); + index_close(idxRel, AccessShareLock); + } + + goto out; + } + + /* * For each index on the partitioned table, find a matching one in the * partition-to-be; if one is not found, create one. */ @@ -15112,6 +15156,7 @@ AttachPartitionEnsureIndexes(Relation rel, Relation attachrel) index_close(idxRel, AccessShareLock); } +out: /* Clean up. */ for (i = 0; i < list_length(attachRelIdxs); i++) index_close(attachrelIdxRels[i], AccessShareLock); diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index e2434774be9..9f8321a3b20 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -1342,10 +1342,16 @@ ProcessUtilitySlow(ParseState *pstate, if (relkind != RELKIND_RELATION && relkind != RELKIND_MATVIEW && - relkind != RELKIND_PARTITIONED_TABLE) + relkind != RELKIND_PARTITIONED_TABLE && + relkind != RELKIND_FOREIGN_TABLE) + elog(ERROR, "unexpected relkind \"%c\" on partition \"%s\"", + relkind, stmt->relation->relname); + + if (relkind == RELKIND_FOREIGN_TABLE && + (stmt->unique || stmt->primary)) ereport(ERROR, - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("cannot create index on partitioned table \"%s\"", + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot create unique index on partitioned table \"%s\"", stmt->relation->relname), errdetail("Table \"%s\" contains partitions that are foreign tables.", stmt->relation->relname))); diff --git a/src/test/regress/expected/foreign_data.out b/src/test/regress/expected/foreign_data.out index 75365501d4a..d613d8e0916 100644 --- a/src/test/regress/expected/foreign_data.out +++ b/src/test/regress/expected/foreign_data.out @@ -752,10 +752,62 @@ ERROR: foreign-data wrapper "dummy" has no handler CREATE TABLE lt1 (a INT) PARTITION BY RANGE (a); CREATE FOREIGN TABLE ft_part1 PARTITION OF lt1 FOR VALUES FROM (0) TO (1000) SERVER s0; -CREATE INDEX ON lt1 (a); -- ERROR -ERROR: cannot create index on partitioned table "lt1" +CREATE INDEX ON lt1 (a); -- skips partition +CREATE UNIQUE INDEX ON lt1 (a); -- ERROR +ERROR: cannot create unique index on partitioned table "lt1" DETAIL: Table "lt1" contains partitions that are foreign tables. +ALTER TABLE lt1 ADD PRIMARY KEY (a); -- ERROR +ERROR: cannot create unique index on partitioned table "lt1" +DETAIL: Table "lt1" contains partitions that are foreign tables. +DROP TABLE lt1; +CREATE TABLE lt1 (a INT) PARTITION BY RANGE (a); +CREATE INDEX ON lt1 (a); +CREATE FOREIGN TABLE ft_part1 + PARTITION OF lt1 FOR VALUES FROM (0) TO (1000) SERVER s0; +CREATE FOREIGN TABLE ft_part2 (a INT) SERVER s0; +ALTER TABLE lt1 ATTACH PARTITION ft_part2 FOR VALUES FROM (1000) TO (2000); +DROP FOREIGN TABLE ft_part1, ft_part2; +CREATE UNIQUE INDEX ON lt1 (a); +ALTER TABLE lt1 ADD PRIMARY KEY (a); +CREATE FOREIGN TABLE ft_part1 + PARTITION OF lt1 FOR VALUES FROM (0) TO (1000) SERVER s0; -- ERROR +ERROR: cannot create foreign partition of partitioned table "lt1" +DETAIL: Table "lt1" contains indexes that are unique. +CREATE FOREIGN TABLE ft_part2 (a INT NOT NULL) SERVER s0; +ALTER TABLE lt1 ATTACH PARTITION ft_part2 + FOR VALUES FROM (1000) TO (2000); -- ERROR +ERROR: cannot attach foreign table "ft_part2" as partition of partitioned table "lt1" +DETAIL: Table "lt1" contains unique indexes. +DROP TABLE lt1; +DROP FOREIGN TABLE ft_part2; +CREATE TABLE lt1 (a INT) PARTITION BY RANGE (a); +CREATE INDEX ON lt1 (a); +CREATE TABLE lt1_part1 + PARTITION OF lt1 FOR VALUES FROM (0) TO (1000) + PARTITION BY RANGE (a); +CREATE FOREIGN TABLE ft_part_1_1 + PARTITION OF lt1_part1 FOR VALUES FROM (0) TO (100) SERVER s0; +CREATE FOREIGN TABLE ft_part_1_2 (a INT) SERVER s0; +ALTER TABLE lt1_part1 ATTACH PARTITION ft_part_1_2 FOR VALUES FROM (100) TO (200); +CREATE UNIQUE INDEX ON lt1 (a); +ERROR: cannot create unique index on partitioned table "lt1" +DETAIL: Table "lt1" contains partitions that are foreign tables. +ALTER TABLE lt1 ADD PRIMARY KEY (a); +ERROR: cannot create unique index on partitioned table "lt1_part1" +DETAIL: Table "lt1_part1" contains partitions that are foreign tables. +DROP FOREIGN TABLE ft_part_1_1, ft_part_1_2; +CREATE UNIQUE INDEX ON lt1 (a); +ALTER TABLE lt1 ADD PRIMARY KEY (a); +CREATE FOREIGN TABLE ft_part_1_1 + PARTITION OF lt1_part1 FOR VALUES FROM (0) TO (100) SERVER s0; +ERROR: cannot create foreign partition of partitioned table "lt1_part1" +DETAIL: Table "lt1_part1" contains indexes that are unique. +CREATE FOREIGN TABLE ft_part_1_2 (a INT NOT NULL) SERVER s0; +ALTER TABLE lt1_part1 ATTACH PARTITION ft_part_1_2 FOR VALUES FROM (100) TO (200); +ERROR: cannot attach foreign table "ft_part_1_2" as partition of partitioned table "lt1_part1" +DETAIL: Table "lt1_part1" contains unique indexes. DROP TABLE lt1; +DROP FOREIGN TABLE ft_part_1_2; -- ALTER FOREIGN TABLE COMMENT ON FOREIGN TABLE ft1 IS 'foreign table'; COMMENT ON FOREIGN TABLE ft1 IS NULL; diff --git a/src/test/regress/sql/foreign_data.sql b/src/test/regress/sql/foreign_data.sql index dab9b62900e..0c36208e4cd 100644 --- a/src/test/regress/sql/foreign_data.sql +++ b/src/test/regress/sql/foreign_data.sql @@ -319,9 +319,49 @@ EXPLAIN SELECT * FROM ft1; -- ERROR CREATE TABLE lt1 (a INT) PARTITION BY RANGE (a); CREATE FOREIGN TABLE ft_part1 PARTITION OF lt1 FOR VALUES FROM (0) TO (1000) SERVER s0; -CREATE INDEX ON lt1 (a); -- ERROR +CREATE INDEX ON lt1 (a); -- skips partition +CREATE UNIQUE INDEX ON lt1 (a); -- ERROR +ALTER TABLE lt1 ADD PRIMARY KEY (a); -- ERROR DROP TABLE lt1; +CREATE TABLE lt1 (a INT) PARTITION BY RANGE (a); +CREATE INDEX ON lt1 (a); +CREATE FOREIGN TABLE ft_part1 + PARTITION OF lt1 FOR VALUES FROM (0) TO (1000) SERVER s0; +CREATE FOREIGN TABLE ft_part2 (a INT) SERVER s0; +ALTER TABLE lt1 ATTACH PARTITION ft_part2 FOR VALUES FROM (1000) TO (2000); +DROP FOREIGN TABLE ft_part1, ft_part2; +CREATE UNIQUE INDEX ON lt1 (a); +ALTER TABLE lt1 ADD PRIMARY KEY (a); +CREATE FOREIGN TABLE ft_part1 + PARTITION OF lt1 FOR VALUES FROM (0) TO (1000) SERVER s0; -- ERROR +CREATE FOREIGN TABLE ft_part2 (a INT NOT NULL) SERVER s0; +ALTER TABLE lt1 ATTACH PARTITION ft_part2 + FOR VALUES FROM (1000) TO (2000); -- ERROR +DROP TABLE lt1; +DROP FOREIGN TABLE ft_part2; + +CREATE TABLE lt1 (a INT) PARTITION BY RANGE (a); +CREATE INDEX ON lt1 (a); +CREATE TABLE lt1_part1 + PARTITION OF lt1 FOR VALUES FROM (0) TO (1000) + PARTITION BY RANGE (a); +CREATE FOREIGN TABLE ft_part_1_1 + PARTITION OF lt1_part1 FOR VALUES FROM (0) TO (100) SERVER s0; +CREATE FOREIGN TABLE ft_part_1_2 (a INT) SERVER s0; +ALTER TABLE lt1_part1 ATTACH PARTITION ft_part_1_2 FOR VALUES FROM (100) TO (200); +CREATE UNIQUE INDEX ON lt1 (a); +ALTER TABLE lt1 ADD PRIMARY KEY (a); +DROP FOREIGN TABLE ft_part_1_1, ft_part_1_2; +CREATE UNIQUE INDEX ON lt1 (a); +ALTER TABLE lt1 ADD PRIMARY KEY (a); +CREATE FOREIGN TABLE ft_part_1_1 + PARTITION OF lt1_part1 FOR VALUES FROM (0) TO (100) SERVER s0; +CREATE FOREIGN TABLE ft_part_1_2 (a INT NOT NULL) SERVER s0; +ALTER TABLE lt1_part1 ATTACH PARTITION ft_part_1_2 FOR VALUES FROM (100) TO (200); +DROP TABLE lt1; +DROP FOREIGN TABLE ft_part_1_2; + -- ALTER FOREIGN TABLE COMMENT ON FOREIGN TABLE ft1 IS 'foreign table'; COMMENT ON FOREIGN TABLE ft1 IS NULL; |