From 05fb5d661925f00106373f1a594be5aca24d9a94 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Thu, 25 Jan 2018 16:11:51 -0300 Subject: [PATCH] Ignore partitioned indexes where appropriate get_relation_info() was too optimistic about opening indexes in partitioned tables, which would raise errors when any queries were planned on such tables. Fix by ignoring any indexes of the partitioned kind. CLUSTER (and ALTER TABLE CLUSTER ON) had a similar problem. Fix by disallowing these commands in partitioned tables. Fallout from 8b08f7d4820f. --- src/backend/commands/cluster.c | 14 ++++++++++++++ src/backend/optimizer/util/plancat.c | 10 ++++++++++ src/test/regress/expected/cluster.out | 8 ++++++++ src/test/regress/expected/indexing.out | 11 +++++++++++ src/test/regress/sql/cluster.sql | 7 +++++++ src/test/regress/sql/indexing.sql | 8 ++++++++ 6 files changed, 58 insertions(+) diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index eb73299199..1701548d84 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -128,6 +128,14 @@ cluster(ClusterStmt *stmt, bool isTopLevel) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot cluster temporary tables of other sessions"))); + /* + * Reject clustering a partitioned table. + */ + if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot cluster a partitioned table"))); + if (stmt->indexname == NULL) { ListCell *index; @@ -482,6 +490,12 @@ mark_index_clustered(Relation rel, Oid indexOid, bool is_internal) Relation pg_index; ListCell *index; + /* Disallow applying to a partitioned table */ + if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot mark index clustered in partitioned table"))); + /* * If the index is already marked clustered, no need to do anything. */ diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index 8c60b35068..60f21711f4 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -207,6 +207,16 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, continue; } + /* + * Ignore partitioned indexes, since they are not usable for + * queries. + */ + if (indexRelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX) + { + index_close(indexRelation, NoLock); + continue; + } + /* * If the index is valid, but cannot yet be used, ignore it; but * mark the plan we are generating as transient. See diff --git a/src/test/regress/expected/cluster.out b/src/test/regress/expected/cluster.out index 82713bfa2c..2bb62212ea 100644 --- a/src/test/regress/expected/cluster.out +++ b/src/test/regress/expected/cluster.out @@ -439,6 +439,14 @@ select * from clstr_temp; drop table clstr_temp; RESET SESSION AUTHORIZATION; +-- Check that partitioned tables cannot be clustered +CREATE TABLE clstrpart (a int) PARTITION BY RANGE (a); +CREATE INDEX clstrpart_idx ON clstrpart (a); +ALTER TABLE clstrpart CLUSTER ON clstrpart_idx; +ERROR: cannot mark index clustered in partitioned table +CLUSTER clstrpart USING clstrpart_idx; +ERROR: cannot cluster a partitioned table +DROP TABLE clstrpart; -- Test CLUSTER with external tuplesorting create table clstr_4 as select * from tenk1; create index cluster_sort on clstr_4 (hundred, thousand, tenthous); diff --git a/src/test/regress/expected/indexing.out b/src/test/regress/expected/indexing.out index ffd4b10c37..e034ad3aad 100644 --- a/src/test/regress/expected/indexing.out +++ b/src/test/regress/expected/indexing.out @@ -31,6 +31,17 @@ ERROR: cannot create unique index on partitioned table "idxpart" create index concurrently on idxpart (a); ERROR: cannot create index on partitioned table "idxpart" concurrently drop table idxpart; +-- Verify bugfix with query on indexed partitioned table with no partitions +-- https://postgr.es/m/20180124162006.pmapfiznhgngwtjf@alvherre.pgsql +CREATE TABLE idxpart (col1 INT) PARTITION BY RANGE (col1); +CREATE INDEX ON idxpart (col1); +CREATE TABLE idxpart_two (col2 INT); +SELECT col2 FROM idxpart_two fk LEFT OUTER JOIN idxpart pk ON (col1 = col2); + col2 +------ +(0 rows) + +DROP table idxpart, idxpart_two; -- If a table without index is attached as partition to a table with -- an index, the index is automatically created create table idxpart (a int, b int, c text) partition by range (a); diff --git a/src/test/regress/sql/cluster.sql b/src/test/regress/sql/cluster.sql index a6c2757efa..522bfeead4 100644 --- a/src/test/regress/sql/cluster.sql +++ b/src/test/regress/sql/cluster.sql @@ -196,6 +196,13 @@ drop table clstr_temp; RESET SESSION AUTHORIZATION; +-- Check that partitioned tables cannot be clustered +CREATE TABLE clstrpart (a int) PARTITION BY RANGE (a); +CREATE INDEX clstrpart_idx ON clstrpart (a); +ALTER TABLE clstrpart CLUSTER ON clstrpart_idx; +CLUSTER clstrpart USING clstrpart_idx; +DROP TABLE clstrpart; + -- Test CLUSTER with external tuplesorting create table clstr_4 as select * from tenk1; diff --git a/src/test/regress/sql/indexing.sql b/src/test/regress/sql/indexing.sql index 2f985ec866..1a9ea89ade 100644 --- a/src/test/regress/sql/indexing.sql +++ b/src/test/regress/sql/indexing.sql @@ -19,6 +19,14 @@ create unique index on idxpart (a); create index concurrently on idxpart (a); drop table idxpart; +-- Verify bugfix with query on indexed partitioned table with no partitions +-- https://postgr.es/m/20180124162006.pmapfiznhgngwtjf@alvherre.pgsql +CREATE TABLE idxpart (col1 INT) PARTITION BY RANGE (col1); +CREATE INDEX ON idxpart (col1); +CREATE TABLE idxpart_two (col2 INT); +SELECT col2 FROM idxpart_two fk LEFT OUTER JOIN idxpart pk ON (col1 = col2); +DROP table idxpart, idxpart_two; + -- If a table without index is attached as partition to a table with -- an index, the index is automatically created create table idxpart (a int, b int, c text) partition by range (a);