Skip to content

Commit 8bca5f9

Browse files
committed
Prevent reindex of invalid indexes on TOAST tables
Such indexes can only be duplicated leftovers of a previously failed REINDEX CONCURRENTLY command, and a valid equivalent is guaranteed to exist. As toast indexes can only be dropped if invalid, reindexing these would lead to useless duplicated indexes that can't be dropped anymore, except if the parent relation is dropped. Thanks to Justin Pryzby for reminding that this problem was reported long ago during the review of the original patch of REINDEX CONCURRENTLY, but the issue was never addressed. Reported-by: Sergei Kornilov, Justin Pryzby Author: Julien Rouhaud Reviewed-by: Michael Paquier Discussion: https://postgr.es/m/36712441546604286%40sas1-890ba5c2334a.qloud-c.yandex.net Discussion: https://postgr.es/m/20200216190835.GA21832@telsasoft.com Backpatch-through: 12
1 parent 4c40b27 commit 8bca5f9

File tree

4 files changed

+62
-0
lines changed

4 files changed

+62
-0
lines changed

src/backend/catalog/index.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3497,6 +3497,17 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
34973497
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
34983498
errmsg("cannot reindex temporary tables of other sessions")));
34993499

3500+
/*
3501+
* Don't allow reindex of an invalid index on TOAST table. This is a
3502+
* leftover from a failed REINDEX CONCURRENTLY, and if rebuilt it would
3503+
* not be possible to drop it anymore.
3504+
*/
3505+
if (IsToastNamespace(RelationGetNamespace(iRel)) &&
3506+
!get_index_isvalid(indexId))
3507+
ereport(ERROR,
3508+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3509+
errmsg("cannot reindex invalid index on TOAST table")));
3510+
35003511
/*
35013512
* Also check for active uses of the index in the current transaction; we
35023513
* don't want to reindex underneath an open indexscan.
@@ -3748,6 +3759,23 @@ reindex_relation(Oid relid, int flags, int options)
37483759
foreach(indexId, indexIds)
37493760
{
37503761
Oid indexOid = lfirst_oid(indexId);
3762+
Oid indexNamespaceId = get_rel_namespace(indexOid);
3763+
3764+
/*
3765+
* Skip any invalid indexes on a TOAST table. These can only be
3766+
* duplicate leftovers from a failed REINDEX CONCURRENTLY, and if
3767+
* rebuilt it would not be possible to drop them anymore.
3768+
*/
3769+
if (IsToastNamespace(indexNamespaceId) &&
3770+
!get_index_isvalid(indexOid))
3771+
{
3772+
ereport(WARNING,
3773+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3774+
errmsg("cannot reindex invalid index \"%s.%s\" on TOAST table, skipping",
3775+
get_namespace_name(indexNamespaceId),
3776+
get_rel_name(indexOid))));
3777+
continue;
3778+
}
37513779

37523780
reindex_index(indexOid, !(flags & REINDEX_REL_CHECK_CONSTRAINTS),
37533781
persistence, options);

src/backend/commands/indexcmds.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2899,6 +2899,16 @@ ReindexRelationConcurrently(Oid relationOid, int options)
28992899
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
29002900
errmsg("cannot reindex system catalogs concurrently")));
29012901

2902+
/*
2903+
* Don't allow reindex for an invalid index on TOAST table, as
2904+
* if rebuild it would not be possible to drop it.
2905+
*/
2906+
if (IsToastNamespace(get_rel_namespace(relationOid)) &&
2907+
!get_index_isvalid(relationOid))
2908+
ereport(ERROR,
2909+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2910+
errmsg("cannot reindex invalid index on TOAST table concurrently")));
2911+
29022912
/* Save the list of relation OIDs in private context */
29032913
oldcontext = MemoryContextSwitchTo(private_context);
29042914

src/backend/utils/cache/lsyscache.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3227,3 +3227,26 @@ get_index_column_opclass(Oid index_oid, int attno)
32273227

32283228
return opclass;
32293229
}
3230+
3231+
/*
3232+
* get_index_isvalid
3233+
*
3234+
* Given the index OID, return pg_index.indisvalid.
3235+
*/
3236+
bool
3237+
get_index_isvalid(Oid index_oid)
3238+
{
3239+
bool isvalid;
3240+
HeapTuple tuple;
3241+
Form_pg_index rd_index;
3242+
3243+
tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
3244+
if (!HeapTupleIsValid(tuple))
3245+
elog(ERROR, "cache lookup failed for index %u", index_oid);
3246+
3247+
rd_index = (Form_pg_index) GETSTRUCT(tuple);
3248+
isvalid = rd_index->indisvalid;
3249+
ReleaseSysCache(tuple);
3250+
3251+
return isvalid;
3252+
}

src/include/utils/lsyscache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ extern char *get_namespace_name_or_temp(Oid nspid);
181181
extern Oid get_range_subtype(Oid rangeOid);
182182
extern Oid get_range_collation(Oid rangeOid);
183183
extern Oid get_index_column_opclass(Oid index_oid, int attno);
184+
extern bool get_index_isvalid(Oid index_oid);
184185

185186
#define type_is_array(typid) (get_element_type(typid) != InvalidOid)
186187
/* type_is_array_domain accepts both plain arrays and domains over arrays */

0 commit comments

Comments
 (0)