Skip to content

Commit 1a368dd

Browse files
committed
Diagnose !indisvalid in more SQL functions.
pgstatindex failed with ERRCODE_DATA_CORRUPTED, of the "can't-happen" class XX. The other functions succeeded on an empty index; they might have malfunctioned if the failed index build left torn I/O or other complex state. Report an ERROR in statistics functions pgstatindex, pgstatginindex, pgstathashindex, and pgstattuple. Report DEBUG1 and skip all index I/O in maintenance functions brin_desummarize_range, brin_summarize_new_values, brin_summarize_range, and gin_clean_pending_list. Back-patch to v11 (all supported versions). Discussion: https://postgr.es/m/20231001195309.a3@google.com
1 parent 3c6a05b commit 1a368dd

File tree

4 files changed

+74
-9
lines changed

4 files changed

+74
-9
lines changed

contrib/pgstattuple/pgstatindex.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,18 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
237237
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
238238
errmsg("cannot access temporary tables of other sessions")));
239239

240+
/*
241+
* A !indisready index could lead to ERRCODE_DATA_CORRUPTED later, so exit
242+
* early. We're capable of assessing an indisready&&!indisvalid index,
243+
* but the results could be confusing. For example, the index's size
244+
* could be too low for a valid index of the table.
245+
*/
246+
if (!rel->rd_index->indisvalid)
247+
ereport(ERROR,
248+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
249+
errmsg("index \"%s\" is not valid",
250+
RelationGetRelationName(rel))));
251+
240252
/*
241253
* Read metapage
242254
*/
@@ -523,6 +535,13 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
523535
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
524536
errmsg("cannot access temporary indexes of other sessions")));
525537

538+
/* see pgstatindex_impl */
539+
if (!rel->rd_index->indisvalid)
540+
ereport(ERROR,
541+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
542+
errmsg("index \"%s\" is not valid",
543+
RelationGetRelationName(rel))));
544+
526545
/*
527546
* Read metapage
528547
*/
@@ -600,6 +619,13 @@ pgstathashindex(PG_FUNCTION_ARGS)
600619
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
601620
errmsg("cannot access temporary indexes of other sessions")));
602621

622+
/* see pgstatindex_impl */
623+
if (!rel->rd_index->indisvalid)
624+
ereport(ERROR,
625+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
626+
errmsg("index \"%s\" is not valid",
627+
RelationGetRelationName(rel))));
628+
603629
/* Get the information we need from the metapage. */
604630
memset(&stats, 0, sizeof(stats));
605631
metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ, LH_META_PAGE);

contrib/pgstattuple/pgstattuple.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,13 @@ pgstat_relation(Relation rel, FunctionCallInfo fcinfo)
259259
}
260260
else if (rel->rd_rel->relkind == RELKIND_INDEX)
261261
{
262+
/* see pgstatindex_impl */
263+
if (!rel->rd_index->indisvalid)
264+
ereport(ERROR,
265+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
266+
errmsg("index \"%s\" is not valid",
267+
RelationGetRelationName(rel))));
268+
262269
switch (rel->rd_rel->relam)
263270
{
264271
case BTREE_AM_OID:

src/backend/access/brin/brin.c

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,8 +1102,14 @@ brin_summarize_range(PG_FUNCTION_ARGS)
11021102
errmsg("could not open parent table of index \"%s\"",
11031103
RelationGetRelationName(indexRel))));
11041104

1105-
/* OK, do it */
1106-
brinsummarize(indexRel, heapRel, heapBlk, true, &numSummarized, NULL);
1105+
/* see gin_clean_pending_list() */
1106+
if (indexRel->rd_index->indisvalid)
1107+
brinsummarize(indexRel, heapRel, heapBlk, true, &numSummarized, NULL);
1108+
else
1109+
ereport(DEBUG1,
1110+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1111+
errmsg("index \"%s\" is not valid",
1112+
RelationGetRelationName(indexRel))));
11071113

11081114
/* Roll back any GUC changes executed by index functions */
11091115
AtEOXact_GUC(false, save_nestlevel);
@@ -1185,12 +1191,21 @@ brin_desummarize_range(PG_FUNCTION_ARGS)
11851191
errmsg("could not open parent table of index \"%s\"",
11861192
RelationGetRelationName(indexRel))));
11871193

1188-
/* the revmap does the hard work */
1189-
do
1194+
/* see gin_clean_pending_list() */
1195+
if (indexRel->rd_index->indisvalid)
11901196
{
1191-
done = brinRevmapDesummarizeRange(indexRel, heapBlk);
1197+
/* the revmap does the hard work */
1198+
do
1199+
{
1200+
done = brinRevmapDesummarizeRange(indexRel, heapBlk);
1201+
}
1202+
while (!done);
11921203
}
1193-
while (!done);
1204+
else
1205+
ereport(DEBUG1,
1206+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1207+
errmsg("index \"%s\" is not valid",
1208+
RelationGetRelationName(indexRel))));
11941209

11951210
relation_close(indexRel, ShareUpdateExclusiveLock);
11961211
relation_close(heapRel, ShareUpdateExclusiveLock);

src/backend/access/gin/ginfast.c

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,7 +1032,6 @@ gin_clean_pending_list(PG_FUNCTION_ARGS)
10321032
Oid indexoid = PG_GETARG_OID(0);
10331033
Relation indexRel = index_open(indexoid, RowExclusiveLock);
10341034
IndexBulkDeleteResult stats;
1035-
GinState ginstate;
10361035

10371036
if (RecoveryInProgress())
10381037
ereport(ERROR,
@@ -1064,8 +1063,26 @@ gin_clean_pending_list(PG_FUNCTION_ARGS)
10641063
RelationGetRelationName(indexRel));
10651064

10661065
memset(&stats, 0, sizeof(stats));
1067-
initGinState(&ginstate, indexRel);
1068-
ginInsertCleanup(&ginstate, true, true, true, &stats);
1066+
1067+
/*
1068+
* Can't assume anything about the content of an !indisready index. Make
1069+
* those a no-op, not an error, so users can just run this function on all
1070+
* indexes of the access method. Since an indisready&&!indisvalid index
1071+
* is merely awaiting missed aminsert calls, we're capable of processing
1072+
* it. Decline to do so, out of an abundance of caution.
1073+
*/
1074+
if (indexRel->rd_index->indisvalid)
1075+
{
1076+
GinState ginstate;
1077+
1078+
initGinState(&ginstate, indexRel);
1079+
ginInsertCleanup(&ginstate, true, true, true, &stats);
1080+
}
1081+
else
1082+
ereport(DEBUG1,
1083+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1084+
errmsg("index \"%s\" is not valid",
1085+
RelationGetRelationName(indexRel))));
10691086

10701087
index_close(indexRel, RowExclusiveLock);
10711088

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy