diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c
index 308aa9e9a6dd4f594671b008e1318571d9a43697..23ff4262d50e8d97cd60e328237c9a97ff561589 100644
--- a/src/backend/access/nbtree/nbtinsert.c
+++ b/src/backend/access/nbtree/nbtinsert.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.37 1999/04/12 16:56:08 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.38 1999/04/22 08:19:59 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -398,6 +398,7 @@ _bt_insertonpg(Relation rel,
 		OffsetNumber maxoff;
 		bool		shifted = false;
 		bool		left_chained = (lpageop->btpo_flags & BTP_CHAIN) ? true : false;
+		bool		is_root = lpageop->btpo_flags & BTP_ROOT;
 
 		/*
 		 * If we have to split leaf page in the chain of duplicates by new
@@ -570,9 +571,20 @@ _bt_insertonpg(Relation rel,
 		 * reasoning).
 		 */
 
+l_spl:;
 		if (stack == (BTStack) NULL)
 		{
-
+			if (!is_root)	/* if this page was not root page */
+			{
+				elog(DEBUG, "btree: concurrent ROOT page split");
+				stack = (BTStack) palloc(sizeof(BTStackData));
+				stack->bts_blkno = lpageop->btpo_parent;
+				stack->bts_offset = InvalidOffsetNumber;
+				stack->bts_btitem = (BTItem) palloc(sizeof(BTItemData));
+				/* bts_btitem will be initialized below */
+				stack->bts_parent = NULL;
+				goto l_spl;
+			}
 			/* create a new root node and release the split buffers */
 			_bt_newroot(rel, buf, rbuf);
 			_bt_relbuf(rel, buf, BT_WRITE);
diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c
index 0cace9d360e2e3fc761db5ca03817febe8d4cdb5..daff4e6bdd4f3f347da17d1f137059646014f2da 100644
--- a/src/backend/access/nbtree/nbtpage.c
+++ b/src/backend/access/nbtree/nbtpage.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtpage.c,v 1.19 1999/03/28 20:31:57 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtpage.c,v 1.20 1999/04/22 08:19:59 vadim Exp $
  *
  *	NOTES
  *	   Postgres btree pages look like ordinary relation pages.	The opaque
@@ -494,24 +494,37 @@ _bt_getstackbuf(Relation rel, BTStack stack, int access)
 	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
 	maxoff = PageGetMaxOffsetNumber(page);
 
-	if (maxoff >= stack->bts_offset)
+	if (stack->bts_offset == InvalidOffsetNumber || 
+		maxoff >= stack->bts_offset)
 	{
-		itemid = PageGetItemId(page, stack->bts_offset);
-		item = (BTItem) PageGetItem(page, itemid);
-
-		/* if the item is where we left it, we're done */
-		if (BTItemSame(item, stack->bts_btitem))
+		/*
+		 * _bt_insertonpg set bts_offset to InvalidOffsetNumber
+		 * in the case of concurrent ROOT page split
+		 */
+		if (stack->bts_offset == InvalidOffsetNumber)
 		{
-			pfree(stack->bts_btitem);
-			item_nbytes = ItemIdGetLength(itemid);
-			item_save = (BTItem) palloc(item_nbytes);
-			memmove((char *) item_save, (char *) item, item_nbytes);
-			stack->bts_btitem = item_save;
-			return buf;
+			i = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
+		}
+		else
+		{
+			itemid = PageGetItemId(page, stack->bts_offset);
+			item = (BTItem) PageGetItem(page, itemid);
+
+			/* if the item is where we left it, we're done */
+			if (BTItemSame(item, stack->bts_btitem))
+			{
+				pfree(stack->bts_btitem);
+				item_nbytes = ItemIdGetLength(itemid);
+				item_save = (BTItem) palloc(item_nbytes);
+				memmove((char *) item_save, (char *) item, item_nbytes);
+				stack->bts_btitem = item_save;
+				return buf;
+			}
+			i = OffsetNumberNext(stack->bts_offset);
 		}
 
 		/* if the item has just moved right on this page, we're done */
-		for (i = OffsetNumberNext(stack->bts_offset);
+		for ( ;
 			 i <= maxoff;
 			 i = OffsetNumberNext(i))
 		{