From 65e0d8c079fb1ad8f69e0c530a11344f029bb691 Mon Sep 17 00:00:00 2001
From: Andrey <amborodin@acm.org>
Date: Thu, 20 Jun 2019 14:40:52 +0500
Subject: [PATCH] Log corruption error codes v2

In some cases we have elog(ERROR) while corruption is certain and
we can give clear error code ERRCODE_DATA_CORRUPTED or
ERRCODE_INDEX_CORRUPTED.
---
 src/backend/access/heap/heapam_handler.c |  4 +-
 src/backend/access/heap/tuptoaster.c     | 53 +++++++++++++-----------
 src/backend/access/nbtree/nbtinsert.c    | 15 ++++---
 src/backend/access/nbtree/nbtpage.c      | 29 ++++++++-----
 src/backend/access/nbtree/nbtsearch.c    |  5 ++-
 5 files changed, 62 insertions(+), 44 deletions(-)

diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c
index a4a28e88ec..ac51d1f48e 100644
--- a/src/backend/access/heap/heapam_handler.c
+++ b/src/backend/access/heap/heapam_handler.c
@@ -426,7 +426,9 @@ tuple_lock_retry:
 
 					/* otherwise xmin should not be dirty... */
 					if (TransactionIdIsValid(SnapshotDirty.xmin))
-						elog(ERROR, "t_xmin is uncommitted in tuple to be updated");
+						ereport(ERROR,
+								(errcode(ERRCODE_DATA_CORRUPTED),
+								 errmsg(ERROR, "t_xmin is uncommitted in tuple to be updated")));
 
 					/*
 					 * If tuple is being updated by other transaction then we
diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c
index 55d6e91d1c..13567ca22b 100644
--- a/src/backend/access/heap/tuptoaster.c
+++ b/src/backend/access/heap/tuptoaster.c
@@ -1966,35 +1966,39 @@ toast_fetch_datum(struct varlena *attr)
 		 * Some checks on the data we've found
 		 */
 		if (residx != nextidx)
-			elog(ERROR, "unexpected chunk number %d (expected %d) for toast value %u in %s",
-				 residx, nextidx,
-				 toast_pointer.va_valueid,
-				 RelationGetRelationName(toastrel));
+			ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED),
+					errmsg("unexpected chunk number %d (expected %d) for toast value %u in %s",
+					residx, nextidx,
+					toast_pointer.va_valueid,
+					RelationGetRelationName(toastrel))));
 		if (residx < numchunks - 1)
 		{
 			if (chunksize != TOAST_MAX_CHUNK_SIZE)
-				elog(ERROR, "unexpected chunk size %d (expected %d) in chunk %d of %d for toast value %u in %s",
-					 chunksize, (int) TOAST_MAX_CHUNK_SIZE,
-					 residx, numchunks,
-					 toast_pointer.va_valueid,
-					 RelationGetRelationName(toastrel));
+				ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED),
+						errmsg("unexpected chunk size %d (expected %d) in chunk %d of %d for toast value %u in %s",
+						 chunksize, (int) TOAST_MAX_CHUNK_SIZE,
+						 residx, numchunks,
+						 toast_pointer.va_valueid,
+						 RelationGetRelationName(toastrel))));
 		}
 		else if (residx == numchunks - 1)
 		{
 			if ((residx * TOAST_MAX_CHUNK_SIZE + chunksize) != ressize)
-				elog(ERROR, "unexpected chunk size %d (expected %d) in final chunk %d for toast value %u in %s",
-					 chunksize,
-					 (int) (ressize - residx * TOAST_MAX_CHUNK_SIZE),
-					 residx,
-					 toast_pointer.va_valueid,
-					 RelationGetRelationName(toastrel));
+				ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED),
+						errmsg("unexpected chunk size %d (expected %d) in final chunk %d for toast value %u in %s",
+						 chunksize,
+						 (int) (ressize - residx * TOAST_MAX_CHUNK_SIZE),
+						 residx,
+						 toast_pointer.va_valueid,
+						 RelationGetRelationName(toastrel))));
 		}
 		else
-			elog(ERROR, "unexpected chunk number %d (out of range %d..%d) for toast value %u in %s",
-				 residx,
-				 0, numchunks - 1,
-				 toast_pointer.va_valueid,
-				 RelationGetRelationName(toastrel));
+			ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED),
+					errmsg("unexpected chunk number %d (out of range %d..%d) for toast value %u in %s",
+					 residx,
+					 0, numchunks - 1,
+					 toast_pointer.va_valueid,
+					 RelationGetRelationName(toastrel))));
 
 		/*
 		 * Copy the data into proper place in our result
@@ -2010,10 +2014,11 @@ toast_fetch_datum(struct varlena *attr)
 	 * Final checks that we successfully fetched the datum
 	 */
 	if (nextidx != numchunks)
-		elog(ERROR, "missing chunk number %d for toast value %u in %s",
-			 nextidx,
-			 toast_pointer.va_valueid,
-			 RelationGetRelationName(toastrel));
+		ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED),
+				errmsg("missing chunk number %d for toast value %u in %s",
+				 nextidx,
+				 toast_pointer.va_valueid,
+				 RelationGetRelationName(toastrel))));
 
 	/*
 	 * End scan and close relations
diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c
index 602f8849d4..002ccfad09 100644
--- a/src/backend/access/nbtree/nbtinsert.c
+++ b/src/backend/access/nbtree/nbtinsert.c
@@ -1568,10 +1568,11 @@ _bt_split(Relation rel, BTScanInsert itup_key, Buffer buf, Buffer cbuf,
 		if (sopaque->btpo_prev != origpagenumber)
 		{
 			memset(rightpage, 0, BufferGetPageSize(rbuf));
-			elog(ERROR, "right sibling's left-link doesn't match: "
-				 "block %u links to %u instead of expected %u in index \"%s\"",
-				 oopaque->btpo_next, sopaque->btpo_prev, origpagenumber,
-				 RelationGetRelationName(rel));
+			ereport(ERROR, (errcode(ERRCODE_INDEX_CORRUPTED),
+					errmsg("right sibling's left-link doesn't match: "
+					 "block %u links to %u instead of expected %u in index \"%s\"",
+					 oopaque->btpo_next, sopaque->btpo_prev, origpagenumber,
+					 RelationGetRelationName(rel))));
 		}
 
 		/*
@@ -1827,8 +1828,10 @@ _bt_insert_parent(Relation rel,
 		_bt_relbuf(rel, rbuf);
 
 		if (pbuf == InvalidBuffer)
-			elog(ERROR, "failed to re-find parent key in index \"%s\" for split pages %u/%u",
-				 RelationGetRelationName(rel), bknum, rbknum);
+			ereport(ERROR,
+					(errcode(ERRCODE_DATA_CORRUPTED),
+					 errmsg(ERROR, "failed to re-find parent key in index \"%s\" for split pages %u/%u",
+					 RelationGetRelationName(rel), bknum, rbknum)));
 
 		/* Recursively update the parent */
 		_bt_insertonpg(rel, NULL, pbuf, buf, stack->bts_parent,
diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c
index de4d4efc46..cda5c05fea 100644
--- a/src/backend/access/nbtree/nbtpage.c
+++ b/src/backend/access/nbtree/nbtpage.c
@@ -1233,8 +1233,10 @@ _bt_lock_branch_parent(Relation rel, BlockNumber child, BTStack stack,
 	stack->bts_btentry = child;
 	pbuf = _bt_getstackbuf(rel, stack);
 	if (pbuf == InvalidBuffer)
-		elog(ERROR, "failed to re-find parent key in index \"%s\" for deletion target page %u",
-			 RelationGetRelationName(rel), child);
+		ereport(ERROR,
+				(errcode(ERRCODE_INDEX_CORRUPTED),
+				 errmsg(ERROR, "failed to re-find parent key in index \"%s\" for deletion target page %u",
+				 RelationGetRelationName(rel), child)));
 	parent = stack->bts_blkno;
 	poffset = stack->bts_offset;
 
@@ -1652,9 +1654,11 @@ _bt_mark_page_halfdead(Relation rel, Buffer leafbuf, BTStack stack)
 	itemid = PageGetItemId(page, nextoffset);
 	itup = (IndexTuple) PageGetItem(page, itemid);
 	if (BTreeInnerTupleGetDownLink(itup) != rightsib)
-		elog(ERROR, "right sibling %u of block %u is not next child %u of block %u in index \"%s\"",
-			 rightsib, target, BTreeInnerTupleGetDownLink(itup),
-			 BufferGetBlockNumber(topparent), RelationGetRelationName(rel));
+		ereport(ERROR,
+					(errcode(ERRCODE_INDEX_CORRUPTED),
+					 errmsg(ERROR, "right sibling %u of block %u is not next child %u of block %u in index \"%s\"",
+					 rightsib, target, BTreeInnerTupleGetDownLink(itup),
+					 BufferGetBlockNumber(topparent), RelationGetRelationName(rel))));
 
 	/*
 	 * Any insert which would have gone on the leaf block will now go to its
@@ -1919,8 +1923,10 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, bool *rightsib_empty)
 			 target, RelationGetRelationName(rel));
 	}
 	if (opaque->btpo_prev != leftsib)
-		elog(ERROR, "left link changed unexpectedly in block %u of index \"%s\"",
-			 target, RelationGetRelationName(rel));
+		ereport(ERROR,
+				(errcode(ERRCODE_INDEX_CORRUPTED),
+				 errmsg(ERROR, "left link changed unexpectedly in block %u of index \"%s\"",
+				 target, RelationGetRelationName(rel))));
 
 	if (target == leafblkno)
 	{
@@ -1952,10 +1958,11 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, bool *rightsib_empty)
 	page = BufferGetPage(rbuf);
 	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
 	if (opaque->btpo_prev != target)
-		elog(ERROR, "right sibling's left-link doesn't match: "
-			 "block %u links to %u instead of expected %u in index \"%s\"",
-			 rightsib, opaque->btpo_prev, target,
-			 RelationGetRelationName(rel));
+		ereport(ERROR, (errcode(ERRCODE_INDEX_CORRUPTED),
+				 errmsg("right sibling's left-link doesn't match: "
+					"block %u links to %u instead of expected %u in index \"%s\"",
+					rightsib, opaque->btpo_prev, target,
+					RelationGetRelationName(rel))));
 	rightsib_is_rightmost = P_RIGHTMOST(opaque);
 	*rightsib_empty = (P_FIRSTDATAKEY(opaque) > PageGetMaxOffsetNumber(page));
 
diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c
index 1f809c24a1..0e148a31c5 100644
--- a/src/backend/access/nbtree/nbtsearch.c
+++ b/src/backend/access/nbtree/nbtsearch.c
@@ -2113,8 +2113,9 @@ _bt_get_endpoint(Relation rel, uint32 level, bool rightmost,
 		if (opaque->btpo.level == level)
 			break;
 		if (opaque->btpo.level < level)
-			elog(ERROR, "btree level %u not found in index \"%s\"",
-				 level, RelationGetRelationName(rel));
+			ereport(ERROR, (errcode(ERRCODE_INDEX_CORRUPTED),
+			 errmsg("btree level %u not found in index \"%s\"",
+				 level, RelationGetRelationName(rel))));
 
 		/* Descend to leftmost or rightmost child page */
 		if (rightmost)
-- 
2.20.1

