From 38ea6aa90e615fc91c138fc1efbc981ef3b434f8 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Fri, 14 Jul 2023 10:12:48 +0900 Subject: Fix updates of indisvalid for partitioned indexes indisvalid is switched to true for partitioned indexes when all its partitions have valid indexes when attaching a new partition, up to the top-most parent if all its leaves are themselves valid when dealing with multiple layers of partitions. The copy of the tuple from pg_index used to switch indisvalid to true came from the relation cache, which is incorrect. Particularly, in the case reported by Shruthi Gowda, executing a series of commands in a single transaction would cause the validation of partitioned indexes to use an incorrect version of a pg_index tuple, as indexes are reloaded after an invalidation request with RelationReloadIndexInfo(), a much faster version than a full index cache rebuild. In this case, the limited information updated in the cache leads to an incorrect version of the tuple used. One of the symptoms reported was the following error, with a replica identity update, for instance: "ERROR: attempted to update invisible tuple" This is incorrect since 8b08f7d, so backpatch all the way down. Reported-by: Shruthi Gowda Author: Michael Paquier Reviewed-by: Shruthi Gowda, Dilip Kumar Discussion: https://postgr.es/m/CAASxf_PBcxax0wW-3gErUyftZ0XrCs3Lrpuhq4-Z3Fak1DoW7Q@mail.gmail.com Backpatch-through: 11 --- src/backend/commands/tablecmds.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'src/backend/commands/tablecmds.c') diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index a9e2a1a1ad2..4dc029f91f1 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -19174,17 +19174,24 @@ validatePartitionedIndex(Relation partedIdx, Relation partedTbl) if (tuples == RelationGetPartitionDesc(partedTbl, true)->nparts) { Relation idxRel; - HeapTuple newtup; + HeapTuple indTup; + Form_pg_index indexForm; idxRel = table_open(IndexRelationId, RowExclusiveLock); + indTup = SearchSysCacheCopy1(INDEXRELID, + ObjectIdGetDatum(RelationGetRelid(partedIdx))); + if (!HeapTupleIsValid(indTup)) + elog(ERROR, "cache lookup failed for index %u", + RelationGetRelid(partedIdx)); + indexForm = (Form_pg_index) GETSTRUCT(indTup); - newtup = heap_copytuple(partedIdx->rd_indextuple); - ((Form_pg_index) GETSTRUCT(newtup))->indisvalid = true; + indexForm->indisvalid = true; updated = true; - CatalogTupleUpdate(idxRel, &partedIdx->rd_indextuple->t_self, newtup); + CatalogTupleUpdate(idxRel, &indTup->t_self, indTup); table_close(idxRel, RowExclusiveLock); + heap_freetuple(indTup); } /* -- cgit v1.2.3