From 7ab6f2da23516e48174f3f144ee9ef19bdc287fb Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Wed, 26 Jan 2011 19:33:50 -0500
Subject: [PATCH] Change inv_truncate() to not repeat its
 systable_getnext_ordered() scan.

In the case where the initial call of systable_getnext_ordered() returned
NULL, this function would nonetheless call it again.  That's undefined
behavior that only by chance failed to not give visibly incorrect results.
Put an if-test around the final loop to prevent that, and in passing
improve some comments.  No back-patch since there's no actual failure.

Per report from YAMAMOTO Takashi.
---
 src/backend/storage/large_object/inv_api.c | 21 ++++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c
index f06bf650756..01e3492cb83 100644
--- a/src/backend/storage/large_object/inv_api.c
+++ b/src/backend/storage/large_object/inv_api.c
@@ -762,6 +762,9 @@ inv_truncate(LargeObjectDesc *obj_desc, int len)
 
 	indstate = CatalogOpenIndexes(lo_heap_r);
 
+	/*
+	 * Set up to find all pages with desired loid and pageno >= target
+	 */
 	ScanKeyInit(&skey[0],
 				Anum_pg_largeobject_loid,
 				BTEqualStrategyNumber, F_OIDEQ,
@@ -841,10 +844,14 @@ inv_truncate(LargeObjectDesc *obj_desc, int len)
 	{
 		/*
 		 * If the first page we found was after the truncation point, we're in
-		 * a hole that we'll fill, but we need to delete the later page.
+		 * a hole that we'll fill, but we need to delete the later page because
+		 * the loop below won't visit it again.
 		 */
-		if (olddata != NULL && olddata->pageno > pageno)
+		if (olddata != NULL)
+		{
+			Assert(olddata->pageno > pageno);
 			simple_heap_delete(lo_heap_r, &oldtuple->t_self);
+		}
 
 		/*
 		 * Write a brand new page.
@@ -873,11 +880,15 @@ inv_truncate(LargeObjectDesc *obj_desc, int len)
 	}
 
 	/*
-	 * Delete any pages after the truncation point
+	 * Delete any pages after the truncation point.  If the initial search
+	 * didn't find a page, then of course there's nothing more to do.
 	 */
-	while ((oldtuple = systable_getnext_ordered(sd, ForwardScanDirection)) != NULL)
+	if (olddata != NULL)
 	{
-		simple_heap_delete(lo_heap_r, &oldtuple->t_self);
+		while ((oldtuple = systable_getnext_ordered(sd, ForwardScanDirection)) != NULL)
+		{
+			simple_heap_delete(lo_heap_r, &oldtuple->t_self);
+		}
 	}
 
 	systable_endscan_ordered(sd);
-- 
GitLab