Fix assertion failure with ALTER TABLE ATTACH PARTITION and indexes
authorMichael Paquier <michael@paquier.xyz>
Tue, 3 Mar 2020 04:55:41 +0000 (13:55 +0900)
committerMichael Paquier <michael@paquier.xyz>
Tue, 3 Mar 2020 04:55:41 +0000 (13:55 +0900)
Using ALTER TABLE ATTACH PARTITION causes an assertion failure when
attempting to work on a partitioned index, because partitioned indexes
cannot have partition bounds.

The grammar of ALTER TABLE ATTACH PARTITION requires partition bounds,
but not ALTER INDEX, so mixing ALTER TABLE with partitioned indexes is
confusing.  Hence, on HEAD, prevent ALTER TABLE to attach a partition if
the relation involved is a partitioned index.  On back-branches, as
applications may rely on the existing behavior, just remove the
culprit assertion.

Reported-by: Alexander Lakhin
Author: Amit Langote, Michael Paquier
Discussion: https://postgr.es/m/16276-5cd1dcc8fb8be7b5@postgresql.org
Backpatch-through: 11

src/backend/parser/parse_utilcmd.c
src/test/regress/expected/indexing.out
src/test/regress/sql/indexing.sql

index ee2d2b54a1d4adb4d8ae53157e1afebf9e92386b..973eab6ae2c848814b7dd69ab72e7d2f93a90ce7 100644 (file)
@@ -3698,8 +3698,16 @@ transformPartitionCmd(CreateStmtContext *cxt, PartitionCmd *cmd)
                                                                                                                 cmd->bound);
                        break;
                case RELKIND_PARTITIONED_INDEX:
-                       /* nothing to check */
-                       Assert(cmd->bound == NULL);
+
+                       /*
+                        * A partitioned index cannot have a partition bound set.  ALTER
+                        * INDEX prevents that with its grammar, but not ALTER TABLE.
+                        */
+                       if (cmd->bound != NULL)
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                                                errmsg("\"%s\" is not a partitioned table",
+                                                               RelationGetRelationName(parentRel))));
                        break;
                case RELKIND_RELATION:
                        /* the table must be partitioned */
index ec1d4eaef4c5f3ae1d42932e2c3274def68dd662..f78865ef81b802fb836614e52da41a0143b66d87 100644 (file)
@@ -121,6 +121,23 @@ Partition of: idxparti2
 No partition constraint
 btree, for table "public.idxpart1"
 
+-- Forbid ALTER TABLE when attaching or detaching an index to a partition.
+create index idxpart_c on only idxpart (c);
+create index idxpart1_c on idxpart1 (c);
+alter table idxpart_c attach partition idxpart1_c for values from (10) to (20);
+ERROR:  "idxpart_c" is not a partitioned table
+alter index idxpart_c attach partition idxpart1_c;
+select relname, relpartbound from pg_class
+  where relname in ('idxpart_c', 'idxpart1_c')
+  order by relname;
+  relname   | relpartbound 
+------------+--------------
+ idxpart1_c | 
+ idxpart_c  | 
+(2 rows)
+
+alter table idxpart_c detach partition idxpart1_c;
+ERROR:  "idxpart_c" is not a table
 drop table idxpart;
 -- If a partition already has an index, don't create a duplicative one
 create table idxpart (a int, b int) partition by range (a, b);
index f6a376791890a161768ffe3c77e77587e6746d32..35d159f41b925a741f41ff3f371c662a438844a4 100644 (file)
@@ -63,6 +63,16 @@ alter table idxpart attach partition idxpart1 for values from (0) to (10);
 \d idxpart1
 \d+ idxpart1_a_idx
 \d+ idxpart1_b_c_idx
+
+-- Forbid ALTER TABLE when attaching or detaching an index to a partition.
+create index idxpart_c on only idxpart (c);
+create index idxpart1_c on idxpart1 (c);
+alter table idxpart_c attach partition idxpart1_c for values from (10) to (20);
+alter index idxpart_c attach partition idxpart1_c;
+select relname, relpartbound from pg_class
+  where relname in ('idxpart_c', 'idxpart1_c')
+  order by relname;
+alter table idxpart_c detach partition idxpart1_c;
 drop table idxpart;
 
 -- If a partition already has an index, don't create a duplicative one