diff --git a/doc/src/sgml/ref/create_index.sgml b/doc/src/sgml/ref/create_index.sgml
index e62ab33905..521e32b197 100644
--- a/doc/src/sgml/ref/create_index.sgml
+++ b/doc/src/sgml/ref/create_index.sgml
@@ -586,10 +586,8 @@ Indexes:
The recommended recovery
method in such cases is to drop the index and try again to perform
- CREATE INDEX CONCURRENTLY. (Another possibility is to rebuild
- the index with REINDEX. However, since REINDEX
- does not support concurrent builds, this option is unlikely to seem
- attractive.)
+ CREATE INDEX CONCURRENTLY. (Another possibility is
+ to rebuild the index with REINDEX INDEX CONCURRENTLY).
diff --git a/doc/src/sgml/ref/reindex.sgml b/doc/src/sgml/ref/reindex.sgml
index e05a76c6d8..303436c89d 100644
--- a/doc/src/sgml/ref/reindex.sgml
+++ b/doc/src/sgml/ref/reindex.sgml
@@ -65,12 +65,11 @@ REINDEX [ ( VERBOSE ) ] { INDEX | TABLE | SCHEMA | DATABASE | SYSTEM } [ CONCURR
- An index build with the CONCURRENTLY option failed, leaving
- an invalid
index. Such indexes are useless but it can be
- convenient to use REINDEX to rebuild them. Note that
- REINDEX will not perform a concurrent build on an invalid index. To build the
- index without interfering with production you should drop the index and
- reissue the CREATE INDEX CONCURRENTLY command.
+ If an index build fails with the CONCURRENTLY option,
+ this index is left as invalid
. Such indexes are useless
+ but it can be convenient to use REINDEX to rebuild
+ them. Note that only REINDEX INDEX is able
+ to perform a concurrent build on an invalid index.
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 46f32c21f9..a1c91b5fb8 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -2776,11 +2776,6 @@ ReindexRelationConcurrently(Oid relationOid, int options)
}
case RELKIND_INDEX:
{
- /*
- * For an index simply add its Oid to list. Invalid indexes
- * cannot be included in list.
- */
- Relation indexRelation = index_open(relationOid, ShareUpdateExclusiveLock);
Oid heapId = IndexGetRelation(relationOid, false);
/* A shared relation cannot be reindexed concurrently */
@@ -2801,25 +2796,13 @@ ReindexRelationConcurrently(Oid relationOid, int options)
/* Track the heap relation of this index for session locks */
heapRelationIds = list_make1_oid(heapId);
+ /*
+ * Save the list of relation OIDs in private context. Note
+ * that invalid indexes are allowed here.
+ */
+ indexIds = lappend_oid(indexIds, relationOid);
+
MemoryContextSwitchTo(oldcontext);
-
- if (!indexRelation->rd_index->indisvalid)
- ereport(WARNING,
- (errcode(ERRCODE_INDEX_CORRUPTED),
- errmsg("cannot reindex concurrently invalid index \"%s.%s\", skipping",
- get_namespace_name(get_rel_namespace(relationOid)),
- get_rel_name(relationOid))));
- else
- {
- /* Save the list of relation OIDs in private context */
- oldcontext = MemoryContextSwitchTo(private_context);
-
- indexIds = lappend_oid(indexIds, relationOid);
-
- MemoryContextSwitchTo(oldcontext);
- }
-
- index_close(indexRelation, NoLock);
break;
}
case RELKIND_PARTITIONED_TABLE:
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 39159e0915..326dc44177 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2118,6 +2118,53 @@ Referenced by:
DROP MATERIALIZED VIEW concur_reindex_matview;
DROP TABLE concur_reindex_tab, concur_reindex_tab2, concur_reindex_tab3;
+-- Check handling of invalid indexes
+CREATE TABLE concur_reindex_tab4 (c1 int);
+INSERT INTO concur_reindex_tab4 VALUES (1), (1), (2);
+-- This trick creates an invalid index.
+CREATE UNIQUE INDEX CONCURRENTLY concur_reindex_ind5 ON concur_reindex_tab4 (c1);
+ERROR: could not create unique index "concur_reindex_ind5"
+DETAIL: Key (c1)=(1) is duplicated.
+-- Reindexing concurrently this index fails with the same failure.
+-- The extra index created is itself invalid, and can be dropped.
+REINDEX INDEX CONCURRENTLY concur_reindex_ind5;
+ERROR: could not create unique index "concur_reindex_ind5_ccnew"
+DETAIL: Key (c1)=(1) is duplicated.
+\d concur_reindex_tab4
+ Table "public.concur_reindex_tab4"
+ Column | Type | Collation | Nullable | Default
+--------+---------+-----------+----------+---------
+ c1 | integer | | |
+Indexes:
+ "concur_reindex_ind5" UNIQUE, btree (c1) INVALID
+ "concur_reindex_ind5_ccnew" UNIQUE, btree (c1) INVALID
+
+DROP INDEX concur_reindex_ind5_ccnew;
+-- This makes the previous failure go away, so the index can become valid.
+DELETE FROM concur_reindex_tab4 WHERE c1 = 1;
+-- The invalid index is not processed when running REINDEX TABLE.
+REINDEX TABLE CONCURRENTLY concur_reindex_tab4;
+WARNING: cannot reindex concurrently invalid index "public.concur_reindex_ind5", skipping
+NOTICE: table "concur_reindex_tab4" has no indexes
+\d concur_reindex_tab4
+ Table "public.concur_reindex_tab4"
+ Column | Type | Collation | Nullable | Default
+--------+---------+-----------+----------+---------
+ c1 | integer | | |
+Indexes:
+ "concur_reindex_ind5" UNIQUE, btree (c1) INVALID
+
+-- But it is fixed with REINDEX INDEX.
+REINDEX INDEX CONCURRENTLY concur_reindex_ind5;
+\d concur_reindex_tab4
+ Table "public.concur_reindex_tab4"
+ Column | Type | Collation | Nullable | Default
+--------+---------+-----------+----------+---------
+ c1 | integer | | |
+Indexes:
+ "concur_reindex_ind5" UNIQUE, btree (c1)
+
+DROP TABLE concur_reindex_tab4;
--
-- REINDEX SCHEMA
--
diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql
index f8141c0ce5..f29b8ca826 100644
--- a/src/test/regress/sql/create_index.sql
+++ b/src/test/regress/sql/create_index.sql
@@ -849,6 +849,26 @@ REINDEX SCHEMA CONCURRENTLY pg_catalog;
DROP MATERIALIZED VIEW concur_reindex_matview;
DROP TABLE concur_reindex_tab, concur_reindex_tab2, concur_reindex_tab3;
+-- Check handling of invalid indexes
+CREATE TABLE concur_reindex_tab4 (c1 int);
+INSERT INTO concur_reindex_tab4 VALUES (1), (1), (2);
+-- This trick creates an invalid index.
+CREATE UNIQUE INDEX CONCURRENTLY concur_reindex_ind5 ON concur_reindex_tab4 (c1);
+-- Reindexing concurrently this index fails with the same failure.
+-- The extra index created is itself invalid, and can be dropped.
+REINDEX INDEX CONCURRENTLY concur_reindex_ind5;
+\d concur_reindex_tab4
+DROP INDEX concur_reindex_ind5_ccnew;
+-- This makes the previous failure go away, so the index can become valid.
+DELETE FROM concur_reindex_tab4 WHERE c1 = 1;
+-- The invalid index is not processed when running REINDEX TABLE.
+REINDEX TABLE CONCURRENTLY concur_reindex_tab4;
+\d concur_reindex_tab4
+-- But it is fixed with REINDEX INDEX.
+REINDEX INDEX CONCURRENTLY concur_reindex_ind5;
+\d concur_reindex_tab4
+DROP TABLE concur_reindex_tab4;
+
--
-- REINDEX SCHEMA
--