From f73fc6eb2908104e4ca0a28106806364cc085c98 Mon Sep 17 00:00:00 2001
From: "Vadim B. Mikheev" <vadim4o@yahoo.com>
Date: Thu, 30 Jul 1998 05:05:05 +0000
Subject: [PATCH] Fix scan adjustment.

---
 src/backend/access/nbtree/nbtree.c  | 105 +++++++++++++++++++++++++++-
 src/backend/access/nbtree/nbtscan.c |  29 +++++++-
 src/include/access/nbtree.h         |  26 ++++---
 3 files changed, 148 insertions(+), 12 deletions(-)

diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index c4ea6aa612..c30d7d56ac 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.27 1998/07/27 19:37:40 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.28 1998/07/30 05:04:49 vadim Exp $
  *
  * NOTES
  *	  This file contains only the public interface routines.
@@ -44,6 +44,8 @@ bool		BuildingBtree = false;		/* see comment in btbuild() */
 bool		FastBuild = true;	/* use sort/build instead of insertion
 								 * build */
 
+static void	_bt_restscan(IndexScanDesc scan);
+
 /*
  *	btbuild() -- build a new btree index.
  *
@@ -374,8 +376,10 @@ btinsert(Relation rel, Datum *datum, char *nulls, ItemPointer ht_ctid, Relation
 	pfree(btitem);
 	pfree(itup);
 
+#if 0
 	/* adjust any active scans that will be affected by this insertion */
 	_bt_adjscans(rel, &(res->pointerData), BT_INSERT);
+#endif
 
 	return (res);
 }
@@ -395,10 +399,28 @@ btgettuple(IndexScanDesc scan, ScanDirection dir)
 	 */
 
 	if (ItemPointerIsValid(&(scan->currentItemData)))
+	{
+		/*
+		 * Now we don't adjust scans on insertion (comments in
+		 * nbtscan.c:_bt_scandel()) and I hope that we will unlock
+		 * current index page before leaving index in LLL: this
+		 * means that current index tuple could be moved right
+		 * before we get here and we have to restore our scan
+		 * position. We save heap TID pointed by current index
+		 * tuple and use it. This will work untill we start
+		 * to re-use (move heap tuples) without vacuum...
+		 * 		- vadim 07/29/98
+		 */
+		_bt_restscan(scan);
 		res = _bt_next(scan, dir);
+	}
 	else
 		res = _bt_first(scan, dir);
-
+	
+	/* Save heap TID to use it in _bt_restscan */
+	if (res)
+		((BTScanOpaque)scan->opaque)->curHeapIptr = res->heap_iptr;
+	
 	return ((char *) res);
 }
 
@@ -555,6 +577,7 @@ btmarkpos(IndexScanDesc scan)
 								   BufferGetBlockNumber(so->btso_curbuf),
 									 BT_READ);
 		scan->currentMarkData = scan->currentItemData;
+		so->mrkHeapIptr = so->curHeapIptr;
 	}
 }
 
@@ -585,6 +608,7 @@ btrestrpos(IndexScanDesc scan)
 									 BT_READ);
 
 		scan->currentItemData = scan->currentMarkData;
+		so->curHeapIptr = so->mrkHeapIptr;
 	}
 }
 
@@ -598,3 +622,80 @@ btdelete(Relation rel, ItemPointer tid)
 	/* delete the data from the page */
 	_bt_pagedel(rel, tid);
 }
+
+/*
+ * Reasons are in btgettuple... We have to find index item that
+ * points to heap tuple returned by previous call to btgettuple().
+ */
+static void
+_bt_restscan(IndexScanDesc scan)
+{
+	Relation		rel = scan->relation;
+	BTScanOpaque	so = (BTScanOpaque) scan->opaque;
+	Buffer			buf = so->btso_curbuf;
+	Page			page = BufferGetPage(buf);
+	ItemPointer		current = &(scan->currentItemData);
+	OffsetNumber	offnum = ItemPointerGetOffsetNumber(current),
+					maxoff = PageGetMaxOffsetNumber(page);
+	BTPageOpaque	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	ItemPointerData	target = so->curHeapIptr;
+	BTItem			item;
+	BlockNumber		blkno;
+
+	if (maxoff >= offnum)
+	{
+		/* 
+		 * if the item is where we left it or has just moved right 
+		 * on this page, we're done 
+		 */
+		for ( ;
+			 offnum <= maxoff;
+			 offnum = OffsetNumberNext(offnum))
+		{
+			item = (BTItem) PageGetItem(page, PageGetItemId(page, offnum));
+			if (item->bti_itup.t_tid.ip_blkid.bi_hi == \
+					target.ip_blkid.bi_hi && \
+				item->bti_itup.t_tid.ip_blkid.bi_lo == \
+					target.ip_blkid.bi_lo && \
+				item->bti_itup.t_tid.ip_posid == target.ip_posid)
+			{
+				current->ip_posid = offnum;
+				return;
+			}
+		}
+	}
+
+	/* 
+	 * By here, the item we're looking for moved right at least one page 
+	 */
+	for (;;)
+	{
+		if (P_RIGHTMOST(opaque))
+			elog(FATAL, "_bt_restscan: my bits moved right off the end of the world!");
+
+		blkno = opaque->btpo_next;
+		_bt_relbuf(rel, buf, BT_READ);
+		buf = _bt_getbuf(rel, blkno, BT_READ);
+		page = BufferGetPage(buf);
+		maxoff = PageGetMaxOffsetNumber(page);
+		opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+
+		/* see if it's on this page */
+		for (offnum = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY ;
+			 offnum <= maxoff;
+			 offnum = OffsetNumberNext(offnum))
+		{
+			item = (BTItem) PageGetItem(page, PageGetItemId(page, offnum));
+			if (item->bti_itup.t_tid.ip_blkid.bi_hi == \
+					target.ip_blkid.bi_hi && \
+				item->bti_itup.t_tid.ip_blkid.bi_lo == \
+					target.ip_blkid.bi_lo && \
+				item->bti_itup.t_tid.ip_posid == target.ip_posid)
+			{
+				ItemPointerSet(current, blkno, offnum);
+				so->btso_curbuf = buf;
+				return;
+			}
+		}
+	}
+}
diff --git a/src/backend/access/nbtree/nbtscan.c b/src/backend/access/nbtree/nbtscan.c
index 8fc6e736c6..7aa9d2ac57 100644
--- a/src/backend/access/nbtree/nbtscan.c
+++ b/src/backend/access/nbtree/nbtscan.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/nbtree/Attic/nbtscan.c,v 1.14 1998/06/15 19:27:57 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/nbtree/Attic/nbtscan.c,v 1.15 1998/07/30 05:04:50 vadim Exp $
  *
  *
  * NOTES
@@ -30,6 +30,7 @@
 #include <postgres.h>
 
 #include <storage/bufpage.h>
+#include <storage/bufmgr.h>
 #include <access/nbtree.h>
 
 typedef struct BTScanListData
@@ -145,9 +146,16 @@ _bt_scandel(IndexScanDesc scan, int op, BlockNumber blkno, OffsetNumber offno)
 	{
 		switch (op)
 		{
+/*
+ * Problems occure when current scan page is splitted!
+ * We saw "Non-functional updates" (ie index tuples were read twice)
+ * and partial updates ("good" tuples were not read at all) - due to
+ * losing scan position here. Look @ nbtree.c:btgettuple()
+ * what we do now...		- vadim 07/29/98
 			case BT_INSERT:
 				_bt_step(scan, &buf, ForwardScanDirection);
 				break;
+ */
 			case BT_DELETE:
 				_bt_step(scan, &buf, BackwardScanDirection);
 				break;
@@ -156,6 +164,14 @@ _bt_scandel(IndexScanDesc scan, int op, BlockNumber blkno, OffsetNumber offno)
 				/* NOTREACHED */
 		}
 		so->btso_curbuf = buf;
+		if (ItemPointerIsValid(current))
+		{
+			Page	page = BufferGetPage(buf);
+			BTItem	btitem = (BTItem) PageGetItem(page, 
+					PageGetItemId(page, ItemPointerGetOffsetNumber(current)));
+			
+			so->curHeapIptr = btitem->bti_itup.t_tid;
+		}
 	}
 
 	current = &(scan->currentMarkData);
@@ -173,9 +189,12 @@ _bt_scandel(IndexScanDesc scan, int op, BlockNumber blkno, OffsetNumber offno)
 		buf = so->btso_curbuf;
 		switch (op)
 		{
+/*
+ * ...comments are above...
 			case BT_INSERT:
 				_bt_step(scan, &buf, ForwardScanDirection);
 				break;
+ */
 			case BT_DELETE:
 				_bt_step(scan, &buf, BackwardScanDirection);
 				break;
@@ -188,6 +207,14 @@ _bt_scandel(IndexScanDesc scan, int op, BlockNumber blkno, OffsetNumber offno)
 		tmp = *current;
 		*current = scan->currentItemData;
 		scan->currentItemData = tmp;
+		if (ItemPointerIsValid(current))
+		{
+			Page	page = BufferGetPage(buf);
+			BTItem	btitem = (BTItem) PageGetItem(page, 
+					PageGetItemId(page, ItemPointerGetOffsetNumber(current)));
+			
+			so->mrkHeapIptr = btitem->bti_itup.t_tid;
+		}
 	}
 }
 
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
index c701200556..5e3d03af3b 100644
--- a/src/include/access/nbtree.h
+++ b/src/include/access/nbtree.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nbtree.h,v 1.20 1998/02/26 04:40:22 momjian Exp $
+ * $Id: nbtree.h,v 1.21 1998/07/30 05:05:05 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -62,18 +62,26 @@ typedef BTPageOpaqueData *BTPageOpaque;
  *	semop() calls, which are expensive.
  *
  *	And it's used to remember actual scankey info (we need in it
- *	if some scankeys evaled at runtime.
+ *	if some scankeys evaled at runtime).
+ *
+ *	curHeapIptr & mrkHeapIptr are heap iptr-s from current/marked
+ *	index tuples: we don't adjust scans on insertions (and, if LLL
+ *	is ON, don't hold locks on index pages between passes) - we
+ *	use these pointers to restore index scan positions...
+ *		- vadim 07/29/98
  */
 
 typedef struct BTScanOpaqueData
 {
-	Buffer		btso_curbuf;
-	Buffer		btso_mrkbuf;
-	uint16		qual_ok;		/* 0 for quals like key == 1 && key > 2 */
-	uint16		numberOfKeys;	/* number of keys */
-	uint16		numberOfFirstKeys;		/* number of keys for 1st
-										 * attribute */
-	ScanKey		keyData;		/* key descriptor */
+	Buffer			btso_curbuf;
+	Buffer			btso_mrkbuf;
+	ItemPointerData	curHeapIptr;
+	ItemPointerData	mrkHeapIptr;
+	uint16			qual_ok;		/* 0 for quals like key == 1 && key > 2 */
+	uint16			numberOfKeys;	/* number of keys */
+	uint16			numberOfFirstKeys;		/* number of keys for 1st
+											 * attribute */
+	ScanKey			keyData;		/* key descriptor */
 } BTScanOpaqueData;
 
 typedef BTScanOpaqueData *BTScanOpaque;
-- 
2.24.1