diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 0b750e72a7d53408b95a4cf5728f6ac720b65892..eeacff56c9d82a0d09eb7d953cea0d64f378a8c8 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.204 2005/11/26 03:03:07 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.205 2005/11/26 05:03:06 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -194,9 +194,7 @@ heapgettup(HeapScanDesc scan,
 		   ScanKey key)
 {
 	HeapTuple	tuple = &(scan->rs_ctup);
-	ItemPointer tid = &(tuple->t_self);
 	Snapshot	snapshot = scan->rs_snapshot;
-	BlockNumber	pages = scan->rs_nblocks;
 	BlockNumber page;
 	Page		dp;
 	int			lines;
@@ -204,52 +202,45 @@ heapgettup(HeapScanDesc scan,
 	int			linesleft;
 	ItemId		lpp;
 
-	if (!scan->rs_inited)
-	{
-		/*
-		 * return null immediately if relation is empty
-		 */
-		if (pages == 0)
-		{
-			Assert(!BufferIsValid(scan->rs_cbuf));
-			tuple->t_data = NULL;
-			return;
-		}
-	}
-	else
-	{
-		/* resuming scan from tuple indicated by scan->rs_ctup.t_self */
-		Assert(ItemPointerIsValid(tid));
-	}
-
 	/*
 	 * calculate next starting lineoff, given scan direction
 	 */
-	if (dir == 0)
+	if (dir > 0)
 	{
 		/*
-		 * ``no movement'' scan direction: refetch prior tuple
+		 * forward scan direction
 		 */
 		if (!scan->rs_inited)
 		{
-			Assert(!BufferIsValid(scan->rs_cbuf));
-			tuple->t_data = NULL;
-			return;
+			/*
+			 * return null immediately if relation is empty
+			 */
+			if (scan->rs_nblocks == 0)
+			{
+				Assert(!BufferIsValid(scan->rs_cbuf));
+				tuple->t_data = NULL;
+				return;
+			}
+			page = 0;							/* first page */
+			heapgetpage(scan, page);
+			lineoff = FirstOffsetNumber;		/* first offnum */
+			scan->rs_inited = true;
+		}
+		else
+		{
+			/* continue from previously returned page/tuple */
+			page = scan->rs_cblock;				/* current page */
+			lineoff =							/* next offnum */
+				OffsetNumberNext(ItemPointerGetOffsetNumber(&(tuple->t_self)));
 		}
 
-		page = ItemPointerGetBlockNumber(tid);
-		if (page != scan->rs_cblock)
-			heapgetpage(scan, page);
+		LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
 
-		/* Since the tuple was previously fetched, needn't lock page here */
 		dp = (Page) BufferGetPage(scan->rs_cbuf);
-		lineoff = ItemPointerGetOffsetNumber(tid);
-		lpp = PageGetItemId(dp, lineoff);
-
-		tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp);
-		tuple->t_len = ItemIdGetLength(lpp);
+		lines = PageGetMaxOffsetNumber(dp);
+		/* page and lineoff now reference the physically next tid */
 
-		return;
+		linesleft = lines - lineoff + 1;
 	}
 	else if (dir < 0)
 	{
@@ -257,12 +248,24 @@ heapgettup(HeapScanDesc scan,
 		 * reverse scan direction
 		 */
 		if (!scan->rs_inited)
-			page = pages - 1;	/* final page */
-		else
-			page = ItemPointerGetBlockNumber(tid);		/* current page */
-
-		if (page != scan->rs_cblock)
+		{
+			/*
+			 * return null immediately if relation is empty
+			 */
+			if (scan->rs_nblocks == 0)
+			{
+				Assert(!BufferIsValid(scan->rs_cbuf));
+				tuple->t_data = NULL;
+				return;
+			}
+			page = scan->rs_nblocks - 1;		/* final page */
 			heapgetpage(scan, page);
+		}
+		else
+		{
+			/* continue from previously returned page/tuple */
+			page = scan->rs_cblock;				/* current page */
+		}
 
 		LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
 
@@ -271,53 +274,44 @@ heapgettup(HeapScanDesc scan,
 
 		if (!scan->rs_inited)
 		{
-			lineoff = lines;	/* final offnum */
+			lineoff = lines;					/* final offnum */
 			scan->rs_inited = true;
 		}
 		else
 		{
-			lineoff =			/* previous offnum */
-				OffsetNumberPrev(ItemPointerGetOffsetNumber(tid));
+			lineoff =							/* previous offnum */
+				OffsetNumberPrev(ItemPointerGetOffsetNumber(&(tuple->t_self)));
 		}
 		/* page and lineoff now reference the physically previous tid */
+
+		linesleft = lineoff;
 	}
 	else
 	{
 		/*
-		 * forward scan direction
+		 * ``no movement'' scan direction: refetch prior tuple
 		 */
 		if (!scan->rs_inited)
 		{
-			page = 0;			/* first page */
-			lineoff = FirstOffsetNumber;		/* first offnum */
-			scan->rs_inited = true;
-		}
-		else
-		{
-			page = ItemPointerGetBlockNumber(tid);		/* current page */
-			lineoff =			/* next offnum */
-				OffsetNumberNext(ItemPointerGetOffsetNumber(tid));
+			Assert(!BufferIsValid(scan->rs_cbuf));
+			tuple->t_data = NULL;
+			return;
 		}
 
+		page = ItemPointerGetBlockNumber(&(tuple->t_self));
 		if (page != scan->rs_cblock)
 			heapgetpage(scan, page);
 
-		LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
-
+		/* Since the tuple was previously fetched, needn't lock page here */
 		dp = (Page) BufferGetPage(scan->rs_cbuf);
-		lines = PageGetMaxOffsetNumber(dp);
-		/* page and lineoff now reference the physically next tid */
-	}
+		lineoff = ItemPointerGetOffsetNumber(&(tuple->t_self));
+		lpp = PageGetItemId(dp, lineoff);
 
-	/* 'dir' is now non-zero */
+		tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp);
+		tuple->t_len = ItemIdGetLength(lpp);
 
-	/*
-	 * calculate number of remaining items to check on this page
-	 */
-	if (dir < 0)
-		linesleft = lineoff;
-	else
-		linesleft = lines - lineoff + 1;
+		return;
+	}
 
 	/*
 	 * advance the scan until we find a qualifying tuple or run out of stuff
@@ -379,7 +373,7 @@ heapgettup(HeapScanDesc scan,
 		/*
 		 * return NULL if we've exhausted all the pages
 		 */
-		if ((dir < 0) ? (page == 0) : (page + 1 >= pages))
+		if ((dir < 0) ? (page == 0) : (page + 1 >= scan->rs_nblocks))
 		{
 			if (BufferIsValid(scan->rs_cbuf))
 				ReleaseBuffer(scan->rs_cbuf);
@@ -432,8 +426,6 @@ heapgettup_pagemode(HeapScanDesc scan,
 					ScanKey key)
 {
 	HeapTuple	tuple = &(scan->rs_ctup);
-	ItemPointer tid = &(tuple->t_self);
-	BlockNumber	pages = scan->rs_nblocks;
 	BlockNumber page;
 	Page		dp;
 	int			lines;
@@ -442,56 +434,42 @@ heapgettup_pagemode(HeapScanDesc scan,
 	int			linesleft;
 	ItemId		lpp;
 
-	if (!scan->rs_inited)
-	{
-		/*
-		 * return null immediately if relation is empty
-		 */
-		if (pages == 0)
-		{
-			Assert(!BufferIsValid(scan->rs_cbuf));
-			tuple->t_data = NULL;
-			return;
-		}
-	}
-	else
-	{
-		/* resuming scan from tuple indicated by scan->rs_ctup.t_self */
-		Assert(ItemPointerIsValid(tid));
-	}
-
 	/*
 	 * calculate next starting lineindex, given scan direction
 	 */
-	if (dir == 0)
+	if (dir > 0)
 	{
 		/*
-		 * ``no movement'' scan direction: refetch prior tuple
+		 * forward scan direction
 		 */
 		if (!scan->rs_inited)
 		{
-			Assert(!BufferIsValid(scan->rs_cbuf));
-			tuple->t_data = NULL;
-			return;
-		}
-
-		page = ItemPointerGetBlockNumber(tid);
-		if (page != scan->rs_cblock)
+			/*
+			 * return null immediately if relation is empty
+			 */
+			if (scan->rs_nblocks == 0)
+			{
+				Assert(!BufferIsValid(scan->rs_cbuf));
+				tuple->t_data = NULL;
+				return;
+			}
+			page = 0;							/* first page */
 			heapgetpage(scan, page);
+			lineindex = 0;
+			scan->rs_inited = true;
+		}
+		else
+		{
+			/* continue from previously returned page/tuple */
+			page = scan->rs_cblock;				/* current page */
+			lineindex = scan->rs_cindex + 1;
+		}
 
-		/* Since the tuple was previously fetched, needn't lock page here */
 		dp = (Page) BufferGetPage(scan->rs_cbuf);
-		lineoff = ItemPointerGetOffsetNumber(tid);
-		lpp = PageGetItemId(dp, lineoff);
-
-		tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp);
-		tuple->t_len = ItemIdGetLength(lpp);
-
-		/* check that rs_cindex is in sync */
-		Assert(scan->rs_cindex < scan->rs_ntuples);
-		Assert(lineoff == scan->rs_vistuples[scan->rs_cindex]);
+		lines = scan->rs_ntuples;
+		/* page and lineindex now reference the next visible tid */
 
-		return;
+		linesleft = lines - lineindex;
 	}
 	else if (dir < 0)
 	{
@@ -499,12 +477,24 @@ heapgettup_pagemode(HeapScanDesc scan,
 		 * reverse scan direction
 		 */
 		if (!scan->rs_inited)
-			page = pages - 1;	/* final page */
-		else
-			page = ItemPointerGetBlockNumber(tid);		/* current page */
-
-		if (page != scan->rs_cblock)
+		{
+			/*
+			 * return null immediately if relation is empty
+			 */
+			if (scan->rs_nblocks == 0)
+			{
+				Assert(!BufferIsValid(scan->rs_cbuf));
+				tuple->t_data = NULL;
+				return;
+			}
+			page = scan->rs_nblocks - 1;		/* final page */
 			heapgetpage(scan, page);
+		}
+		else
+		{
+			/* continue from previously returned page/tuple */
+			page = scan->rs_cblock;				/* current page */
+		}
 
 		dp = (Page) BufferGetPage(scan->rs_cbuf);
 		lines = scan->rs_ntuples;
@@ -519,41 +509,39 @@ heapgettup_pagemode(HeapScanDesc scan,
 			lineindex = scan->rs_cindex - 1;
 		}
 		/* page and lineindex now reference the previous visible tid */
+
+		linesleft = lineindex + 1;
 	}
 	else
 	{
 		/*
-		 * forward scan direction
+		 * ``no movement'' scan direction: refetch prior tuple
 		 */
 		if (!scan->rs_inited)
 		{
-			page = 0;			/* first page */
-			lineindex = 0;
-			scan->rs_inited = true;
-		}
-		else
-		{
-			page = ItemPointerGetBlockNumber(tid);		/* current page */
-			lineindex = scan->rs_cindex + 1;
+			Assert(!BufferIsValid(scan->rs_cbuf));
+			tuple->t_data = NULL;
+			return;
 		}
 
+		page = ItemPointerGetBlockNumber(&(tuple->t_self));
 		if (page != scan->rs_cblock)
 			heapgetpage(scan, page);
 
+		/* Since the tuple was previously fetched, needn't lock page here */
 		dp = (Page) BufferGetPage(scan->rs_cbuf);
-		lines = scan->rs_ntuples;
-		/* page and lineindex now reference the next visible tid */
-	}
+		lineoff = ItemPointerGetOffsetNumber(&(tuple->t_self));
+		lpp = PageGetItemId(dp, lineoff);
 
-	/* 'dir' is now non-zero */
+		tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp);
+		tuple->t_len = ItemIdGetLength(lpp);
 
-	/*
-	 * calculate number of remaining items to check on this page
-	 */
-	if (dir < 0)
-		linesleft = lineindex + 1;
-	else
-		linesleft = lines - lineindex;
+		/* check that rs_cindex is in sync */
+		Assert(scan->rs_cindex < scan->rs_ntuples);
+		Assert(lineoff == scan->rs_vistuples[scan->rs_cindex]);
+
+		return;
+	}
 
 	/*
 	 * advance the scan until we find a qualifying tuple or run out of stuff
@@ -614,7 +602,7 @@ heapgettup_pagemode(HeapScanDesc scan,
 		/*
 		 * return NULL if we've exhausted all the pages
 		 */
-		if ((dir < 0) ? (page == 0) : (page + 1 >= pages))
+		if ((dir < 0) ? (page == 0) : (page + 1 >= scan->rs_nblocks))
 		{
 			if (BufferIsValid(scan->rs_cbuf))
 				ReleaseBuffer(scan->rs_cbuf);
@@ -2743,6 +2731,7 @@ heap_restrpos(HeapScanDesc scan)
 			ReleaseBuffer(scan->rs_cbuf);
 		scan->rs_cbuf = InvalidBuffer;
 		scan->rs_cblock = InvalidBlockNumber;
+		scan->rs_inited = false;
 	}
 	else
 	{