diff options
-rw-r--r-- | src/backend/catalog/index.c | 40 | ||||
-rw-r--r-- | src/backend/catalog/pg_depend.c | 56 | ||||
-rw-r--r-- | src/include/catalog/dependency.h | 3 | ||||
-rw-r--r-- | src/test/regress/expected/create_index.out | 85 | ||||
-rw-r--r-- | src/test/regress/sql/create_index.sql | 43 |
5 files changed, 209 insertions, 18 deletions
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 9b1d5467917..e9399bef14c 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -39,6 +39,7 @@ #include "catalog/heap.h" #include "catalog/index.h" #include "catalog/objectaccess.h" +#include "catalog/partition.h" #include "catalog/pg_am.h" #include "catalog/pg_collation.h" #include "catalog/pg_constraint.h" @@ -1263,7 +1264,13 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, const char indexColNames = lappend(indexColNames, NameStr(att->attname)); } - /* Now create the new index */ + /* + * Now create the new index. + * + * For a partition index, we adjust the partition dependency later, to + * ensure a consistent state at all times. That is why parentIndexRelid + * is not set here. + */ newIndexId = index_create(heapRelation, newName, InvalidOid, /* indexRelationId */ @@ -1395,6 +1402,9 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName) namestrcpy(&newClassForm->relname, NameStr(oldClassForm->relname)); namestrcpy(&oldClassForm->relname, oldName); + /* Copy partition flag to track inheritance properly */ + newClassForm->relispartition = oldClassForm->relispartition; + CatalogTupleUpdate(pg_class, &oldClassTuple->t_self, oldClassTuple); CatalogTupleUpdate(pg_class, &newClassTuple->t_self, newClassTuple); @@ -1555,29 +1565,23 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName) } /* - * Move all dependencies on the old index to the new one + * Swap inheritance relationship with parent index */ - - if (OidIsValid(indexConstraintOid)) + if (get_rel_relispartition(oldIndexId)) { - ObjectAddress myself, - referenced; - - /* Change to having the new index depend on the constraint */ - deleteDependencyRecordsForClass(RelationRelationId, oldIndexId, - ConstraintRelationId, DEPENDENCY_INTERNAL); + List *ancestors = get_partition_ancestors(oldIndexId); + Oid parentIndexRelid = linitial_oid(ancestors); - myself.classId = RelationRelationId; - myself.objectId = newIndexId; - myself.objectSubId = 0; + DeleteInheritsTuple(oldIndexId, parentIndexRelid); + StoreSingleInheritance(newIndexId, parentIndexRelid, 1); - referenced.classId = ConstraintRelationId; - referenced.objectId = indexConstraintOid; - referenced.objectSubId = 0; - - recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL); + list_free(ancestors); } + /* + * Move all dependencies of and on the old index to the new one + */ + changeDependenciesOf(RelationRelationId, oldIndexId, newIndexId); changeDependenciesOn(RelationRelationId, oldIndexId, newIndexId); /* diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c index d63bf5e56d9..f7caedcc02c 100644 --- a/src/backend/catalog/pg_depend.c +++ b/src/backend/catalog/pg_depend.c @@ -396,6 +396,62 @@ changeDependencyFor(Oid classId, Oid objectId, } /* + * Adjust all dependency records to come from a different object of the same type + * + * classId/oldObjectId specify the old referencing object. + * newObjectId is the new referencing object (must be of class classId). + * + * Returns the number of records updated. + */ +long +changeDependenciesOf(Oid classId, Oid oldObjectId, + Oid newObjectId) +{ + long count = 0; + Relation depRel; + ScanKeyData key[2]; + SysScanDesc scan; + HeapTuple tup; + + depRel = table_open(DependRelationId, RowExclusiveLock); + + ScanKeyInit(&key[0], + Anum_pg_depend_classid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(classId)); + ScanKeyInit(&key[1], + Anum_pg_depend_objid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(oldObjectId)); + + scan = systable_beginscan(depRel, DependDependerIndexId, true, + NULL, 2, key); + + while (HeapTupleIsValid((tup = systable_getnext(scan)))) + { + Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup); + + /* make a modifiable copy */ + tup = heap_copytuple(tup); + depform = (Form_pg_depend) GETSTRUCT(tup); + + depform->objid = newObjectId; + + CatalogTupleUpdate(depRel, &tup->t_self, tup); + + heap_freetuple(tup); + + count++; + } + + systable_endscan(scan); + + table_close(depRel, RowExclusiveLock); + + return count; +} + +/* * Adjust all dependency records to point to a different object of the same type * * refClassId/oldRefObjectId specify the old referenced object. diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index 4f9dde9df9d..57545b70d88 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -199,6 +199,9 @@ extern long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId); +extern long changeDependenciesOf(Oid classId, Oid oldObjectId, + Oid newObjectId); + extern long changeDependenciesOn(Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId); diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out index f9b4768aeec..39159e09157 100644 --- a/src/test/regress/expected/create_index.out +++ b/src/test/regress/expected/create_index.out @@ -2001,6 +2001,91 @@ SELECT obj_description('testcomment_idx1'::regclass, 'pg_class'); (1 row) DROP TABLE testcomment; +-- Partitions +-- Create some partitioned tables +CREATE TABLE concur_reindex_part (c1 int, c2 int) PARTITION BY RANGE (c1); +CREATE TABLE concur_reindex_part_0 PARTITION OF concur_reindex_part + FOR VALUES FROM (0) TO (10) PARTITION BY list (c2); +CREATE TABLE concur_reindex_part_0_1 PARTITION OF concur_reindex_part_0 + FOR VALUES IN (1); +CREATE TABLE concur_reindex_part_0_2 PARTITION OF concur_reindex_part_0 + FOR VALUES IN (2); +-- This partitioned table will have no partitions. +CREATE TABLE concur_reindex_part_10 PARTITION OF concur_reindex_part + FOR VALUES FROM (10) TO (20) PARTITION BY list (c2); +-- Create some partitioned indexes +CREATE INDEX concur_reindex_part_index ON ONLY concur_reindex_part (c1); +CREATE INDEX concur_reindex_part_index_0 ON ONLY concur_reindex_part_0 (c1); +ALTER INDEX concur_reindex_part_index ATTACH PARTITION concur_reindex_part_index_0; +-- This partitioned index will have no partitions. +CREATE INDEX concur_reindex_part_index_10 ON ONLY concur_reindex_part_10 (c1); +ALTER INDEX concur_reindex_part_index ATTACH PARTITION concur_reindex_part_index_10; +CREATE INDEX concur_reindex_part_index_0_1 ON ONLY concur_reindex_part_0_1 (c1); +ALTER INDEX concur_reindex_part_index_0 ATTACH PARTITION concur_reindex_part_index_0_1; +CREATE INDEX concur_reindex_part_index_0_2 ON ONLY concur_reindex_part_0_2 (c1); +ALTER INDEX concur_reindex_part_index_0 ATTACH PARTITION concur_reindex_part_index_0_2; +SELECT relid, parentrelid, level FROM pg_partition_tree('concur_reindex_part_index') + ORDER BY relid, level; + relid | parentrelid | level +-------------------------------+-----------------------------+------- + concur_reindex_part_index | | 0 + concur_reindex_part_index_0 | concur_reindex_part_index | 1 + concur_reindex_part_index_10 | concur_reindex_part_index | 1 + concur_reindex_part_index_0_1 | concur_reindex_part_index_0 | 2 + concur_reindex_part_index_0_2 | concur_reindex_part_index_0 | 2 +(5 rows) + +-- REINDEX fails for partitioned indexes +REINDEX INDEX concur_reindex_part_index_10; +ERROR: REINDEX is not yet implemented for partitioned indexes +REINDEX INDEX CONCURRENTLY concur_reindex_part_index_10; +ERROR: REINDEX is not yet implemented for partitioned indexes +-- REINDEX is a no-op for partitioned tables +REINDEX TABLE concur_reindex_part_10; +WARNING: REINDEX of partitioned tables is not yet implemented, skipping "concur_reindex_part_10" +NOTICE: table "concur_reindex_part_10" has no indexes +REINDEX TABLE CONCURRENTLY concur_reindex_part_10; +WARNING: REINDEX of partitioned tables is not yet implemented, skipping "concur_reindex_part_10" +NOTICE: table "concur_reindex_part_10" has no indexes +SELECT relid, parentrelid, level FROM pg_partition_tree('concur_reindex_part_index') + ORDER BY relid, level; + relid | parentrelid | level +-------------------------------+-----------------------------+------- + concur_reindex_part_index | | 0 + concur_reindex_part_index_0 | concur_reindex_part_index | 1 + concur_reindex_part_index_10 | concur_reindex_part_index | 1 + concur_reindex_part_index_0_1 | concur_reindex_part_index_0 | 2 + concur_reindex_part_index_0_2 | concur_reindex_part_index_0 | 2 +(5 rows) + +-- REINDEX should preserve dependencies of partition tree. +REINDEX INDEX CONCURRENTLY concur_reindex_part_index_0_1; +REINDEX INDEX CONCURRENTLY concur_reindex_part_index_0_2; +SELECT relid, parentrelid, level FROM pg_partition_tree('concur_reindex_part_index') + ORDER BY relid, level; + relid | parentrelid | level +-------------------------------+-----------------------------+------- + concur_reindex_part_index | | 0 + concur_reindex_part_index_0 | concur_reindex_part_index | 1 + concur_reindex_part_index_10 | concur_reindex_part_index | 1 + concur_reindex_part_index_0_1 | concur_reindex_part_index_0 | 2 + concur_reindex_part_index_0_2 | concur_reindex_part_index_0 | 2 +(5 rows) + +REINDEX TABLE CONCURRENTLY concur_reindex_part_0_1; +REINDEX TABLE CONCURRENTLY concur_reindex_part_0_2; +SELECT relid, parentrelid, level FROM pg_partition_tree('concur_reindex_part_index') + ORDER BY relid, level; + relid | parentrelid | level +-------------------------------+-----------------------------+------- + concur_reindex_part_index | | 0 + concur_reindex_part_index_0 | concur_reindex_part_index | 1 + concur_reindex_part_index_10 | concur_reindex_part_index | 1 + concur_reindex_part_index_0_1 | concur_reindex_part_index_0 | 2 + concur_reindex_part_index_0_2 | concur_reindex_part_index_0 | 2 +(5 rows) + +DROP TABLE concur_reindex_part; -- Check errors -- Cannot run inside a transaction block BEGIN; diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql index 2f0e9a63e6b..f8141c0ce51 100644 --- a/src/test/regress/sql/create_index.sql +++ b/src/test/regress/sql/create_index.sql @@ -789,6 +789,49 @@ SELECT obj_description('testcomment_idx1'::regclass, 'pg_class'); REINDEX TABLE CONCURRENTLY testcomment ; SELECT obj_description('testcomment_idx1'::regclass, 'pg_class'); DROP TABLE testcomment; +-- Partitions +-- Create some partitioned tables +CREATE TABLE concur_reindex_part (c1 int, c2 int) PARTITION BY RANGE (c1); +CREATE TABLE concur_reindex_part_0 PARTITION OF concur_reindex_part + FOR VALUES FROM (0) TO (10) PARTITION BY list (c2); +CREATE TABLE concur_reindex_part_0_1 PARTITION OF concur_reindex_part_0 + FOR VALUES IN (1); +CREATE TABLE concur_reindex_part_0_2 PARTITION OF concur_reindex_part_0 + FOR VALUES IN (2); +-- This partitioned table will have no partitions. +CREATE TABLE concur_reindex_part_10 PARTITION OF concur_reindex_part + FOR VALUES FROM (10) TO (20) PARTITION BY list (c2); +-- Create some partitioned indexes +CREATE INDEX concur_reindex_part_index ON ONLY concur_reindex_part (c1); +CREATE INDEX concur_reindex_part_index_0 ON ONLY concur_reindex_part_0 (c1); +ALTER INDEX concur_reindex_part_index ATTACH PARTITION concur_reindex_part_index_0; +-- This partitioned index will have no partitions. +CREATE INDEX concur_reindex_part_index_10 ON ONLY concur_reindex_part_10 (c1); +ALTER INDEX concur_reindex_part_index ATTACH PARTITION concur_reindex_part_index_10; +CREATE INDEX concur_reindex_part_index_0_1 ON ONLY concur_reindex_part_0_1 (c1); +ALTER INDEX concur_reindex_part_index_0 ATTACH PARTITION concur_reindex_part_index_0_1; +CREATE INDEX concur_reindex_part_index_0_2 ON ONLY concur_reindex_part_0_2 (c1); +ALTER INDEX concur_reindex_part_index_0 ATTACH PARTITION concur_reindex_part_index_0_2; +SELECT relid, parentrelid, level FROM pg_partition_tree('concur_reindex_part_index') + ORDER BY relid, level; +-- REINDEX fails for partitioned indexes +REINDEX INDEX concur_reindex_part_index_10; +REINDEX INDEX CONCURRENTLY concur_reindex_part_index_10; +-- REINDEX is a no-op for partitioned tables +REINDEX TABLE concur_reindex_part_10; +REINDEX TABLE CONCURRENTLY concur_reindex_part_10; +SELECT relid, parentrelid, level FROM pg_partition_tree('concur_reindex_part_index') + ORDER BY relid, level; +-- REINDEX should preserve dependencies of partition tree. +REINDEX INDEX CONCURRENTLY concur_reindex_part_index_0_1; +REINDEX INDEX CONCURRENTLY concur_reindex_part_index_0_2; +SELECT relid, parentrelid, level FROM pg_partition_tree('concur_reindex_part_index') + ORDER BY relid, level; +REINDEX TABLE CONCURRENTLY concur_reindex_part_0_1; +REINDEX TABLE CONCURRENTLY concur_reindex_part_0_2; +SELECT relid, parentrelid, level FROM pg_partition_tree('concur_reindex_part_index') + ORDER BY relid, level; +DROP TABLE concur_reindex_part; -- Check errors -- Cannot run inside a transaction block |