as if ALTER INDEX ATTACH PARTITION 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 UNIQUE indexes on the target table. (See also
.)
See the similar form of
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 UNIQUE
+ indexes on the parent table. (See also
ALTER TABLE ATTACH PARTITION .)
int maplen;
childrel = table_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))));
+
+ table_close(childrel, lockmode);
+ continue;
+ }
+
childidxs = RelationGetIndexList(childrel);
attmap =
convert_tuples_by_name_map(RelationGetDescr(childrel),
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"));
i++;
}
+ /*
+ * 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.
index_close(idxRel, AccessShareLock);
}
+out:
/* Clean up. */
for (i = 0; i < list_length(attachRelIdxs); i++)
index_close(attachrelIdxRels[i], AccessShareLock);
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)));
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;
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;