Ignore partitioned indexes where appropriate
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Thu, 25 Jan 2018 19:11:51 +0000 (16:11 -0300)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Thu, 25 Jan 2018 19:12:15 +0000 (16:12 -0300)
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
src/backend/optimizer/util/plancat.c
src/test/regress/expected/cluster.out
src/test/regress/expected/indexing.out
src/test/regress/sql/cluster.sql
src/test/regress/sql/indexing.sql

index eb73299199a022a5cceebba67b8b2fe43085713b..1701548d84439b1639fa0ec64a47ef4a2485ac41 100644 (file)
@@ -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.
         */
index 8c60b35068ed40a3b26dcf00f3ab30ae5f1fe20e..60f21711f4fb05308c6bc94f5c2331df7771b68d 100644 (file)
@@ -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
index 82713bfa2c7067b33ab219d7d88566eadf2e125b..2bb62212ea7659628db6bd6550ab805d2849a818 100644 (file)
@@ -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);
index ffd4b10c37e6212d19e1ba90cf748e51ad5838ce..e034ad3aadb5241d2f1f6a6f5272adaee91a1776 100644 (file)
@@ -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);
index a6c2757efaaac6ebce58ed3265b7141d3bde3522..522bfeead4159e879075bc980792abf769bed31d 100644 (file)
@@ -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;
index 2f985ec8667d741d573e002b10f1684e35ea391e..1a9ea89adebb58130b72c30c7c921bc234ebeee7 100644 (file)
@@ -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);