8000 Diagnose !indisvalid in more SQL functions. · postgres/postgres@bae063d · GitHub
[go: up one dir, main page]

Skip to content

Commit bae063d

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 e04509f commit bae063d

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
@@ -236,6 +236,18 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
236236
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
237237
errmsg("cannot access temporary tables of other sessions")));
238238

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

552+
/* see pgstatindex_impl */
553+
if (!rel->rd_index->indisvalid)
554+
ereport(ERROR,
555+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
556+
errmsg("index \"%s\" is not valid",
557+
RelationGetRelationName(rel))));
558+
540559
/*
541560
* Read metapage
542561
*/
@@ -614,6 +633,13 @@ pgstathashindex(PG_FUNCTION_ARGS)
614633
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
615634
errmsg("cannot access temporary indexes of other sessions")));
616635

636+
/* see pgstatindex_impl */
637+
if (!rel->rd_index->indisvalid)
638+
ereport(ERROR,
639+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
640+
errmsg("index \"%s\" is not valid",
641+
RelationGetRelationName(rel))));
642+
617643
/* Get the information we need from the metapage. */
618644
memset(&stats, 0, sizeof(stats));
619645
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
case RELKIND_SEQUENCE:
260260
return pgstat_heap(rel, fcinfo);
261261
case RELKIND_INDEX:
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
@@ -1036,8 +1036,14 @@ brin_summarize_range(PG_FUNCTION_ARGS)
10361036
errmsg("could not open parent table of index %s",
10371037
RelationGetRelationName(indexRel))));
10381038

1039-
/* OK, do it */
1040-
brinsummarize(indexRel, heapRel, heapBlk, true, &numSummarized, NULL);
1039+
/* see gin_clean_pending_list() */
1040+
if (indexRel->rd_index->indisvalid)
1041+
brinsummarize(indexRel, heapRel, heapBlk, true, &numSummarized, NULL);
1042+
else
1043+
ereport(DEBUG1,
1044+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1045+
errmsg("index \"%s\" is not valid",
1046+
RelationGetRelationName(indexRel))));
10411047

10421048
/* Roll back any GUC changes executed by index functions */
10431049
AtEOXact_GUC(false, save_nestlevel);
@@ -1122,12 +1128,21 @@ brin_desummarize_range(PG_FUNCTION_ARGS)
11221128
errmsg("could not open parent table of index %s",
11231129
RelationGetRelationName(indexRel))));
11241130

1125-
/* the revmap does the hard work */
1126-
do
1131+
/* see gin_clean_pending_list() */
1132+
if (indexRel->rd_index->indisvalid)
11271133
{
1128-
done = brinRevmapDesummarizeRange(indexRel, heapBlk);
1134+
/* the revmap does the hard work */
1135+
do
1136+
{
1137+
done = brinRevmapDesummarizeRange(indexRel, heapBlk);
1138+
}
1139+
while (!done);
11291140
}
1130-
while (!done);
1141+
else
1142+
ereport(DEBUG1,
1143+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1144+
errmsg("index \"%s\" is not valid",
1145+
RelationGetRelationName(indexRel))));
11311146

11321147
relation_close(indexRel, ShareUpdateExclusiveLock);
11331148
relation_close(heapRel, ShareUpdateExclusiveLock);

src/backend/access/gin/ginfast.c

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,7 +1018,6 @@ gin_clean_pending_list(PG_FUNCTION_ARGS)
10181018
Oid indexoid = PG_GETARG_OID(0);
10191019
Relation indexRel = index_open(indexoid, AccessShareLock);
10201020
IndexBulkDeleteResult stats;
1021-
GinState ginstate;
10221021

10231022
if (RecoveryInProgress())
10241023
ereport(ERROR,
@@ -1050,8 +1049,26 @@ gin_clean_pending_list(PG_FUNCTION_ARGS)
10501049
RelationGetRelationName(indexRel));
10511050

10521051
memset(&stats, 0, sizeof(stats));
1053-
initGinState(&ginstate, indexRel);
1054-
ginInsertCleanup(&ginstate, true, true, true, &stats);
1052+
1053+
/*
1054+
* Can't assume anything about the content of an !indisready index. Make
1055+
* those a no-op, not an error, so users can just run this function on all
1056+
* indexes of the access method. Since an indisready&&!indisvalid index
1057+
* is merely awaiting missed aminsert calls, we're capable of processing
1058+
* it. Decline to do so, out of an abundance of caution.
1059+
*/
1060+
if (indexRel->rd_index->indisvalid)
1061+
{
1062+
GinState ginstate;
1063+
1064+
initGinState(&ginstate, indexRel);
1065+
ginInsertCleanup(&ginstate, true, true, true, &stats);
1066+
}
1067+
else
1068+
ereport(DEBUG1,
1069+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1070+
errmsg("index \"%s\" is not valid",
1071+
RelationGetRelationName(indexRel))));
10551072

10561073
index_close(indexRel, AccessShareLock);
10571074

0 commit comments

Comments
 (0)
0