From 3f7fbf85dc5b42dfd33c803efe6c90533773576a Mon Sep 17 00:00:00 2001
From: "Vadim B. Mikheev" <vadim4o@yahoo.com>
Date: Tue, 15 Dec 1998 12:47:01 +0000
Subject: [PATCH] Initial MVCC code. New code for locking buffer' context.

---
 src/backend/access/gist/gist.c             |  17 +-
 src/backend/access/gist/gistscan.c         |   5 +
 src/backend/access/hash/hashpage.c         |  20 +-
 src/backend/access/heap/heapam.c           | 496 +++++++++---------
 src/backend/access/heap/hio.c              |  71 +--
 src/backend/access/heap/stats.c            |   8 +-
 src/backend/access/index/indexam.c         |   6 +-
 src/backend/access/nbtree/nbtinsert.c      |  27 +-
 src/backend/access/nbtree/nbtpage.c        |  20 +-
 src/backend/access/rtree/rtree.c           |  19 +-
 src/backend/access/rtree/rtscan.c          |   7 +-
 src/backend/access/transam/transam.c       |  21 +-
 src/backend/access/transam/transsup.c      |  33 +-
 src/backend/access/transam/xact.c          |   7 +-
 src/backend/catalog/aclchk.c               |   4 +-
 src/backend/catalog/heap.c                 |  32 +-
 src/backend/catalog/index.c                |  22 +-
 src/backend/catalog/pg_operator.c          |  10 +-
 src/backend/catalog/pg_type.c              |  10 +-
 src/backend/commands/async.c               |  30 +-
 src/backend/commands/command.c             |   4 +-
 src/backend/commands/copy.c                |  23 +-
 src/backend/commands/dbcommands.c          |   4 +-
 src/backend/commands/defind.c              |   4 +-
 src/backend/commands/proclang.c            |   2 +-
 src/backend/commands/remove.c              |  14 +-
 src/backend/commands/rename.c              |   6 +-
 src/backend/commands/sequence.c            |  42 +-
 src/backend/commands/trigger.c             | 155 +++---
 src/backend/commands/user.c                |  20 +-
 src/backend/commands/vacuum.c              |  12 +-
 src/backend/executor/execMain.c            |  97 ++--
 src/backend/executor/execUtils.c           |  31 +-
 src/backend/executor/nodeHash.c            |  10 +-
 src/backend/parser/gram.c                  |   2 +-
 src/backend/parser/parse_func.c            |   4 +-
 src/backend/rewrite/rewriteRemove.c        |   6 +-
 src/backend/rewrite/rewriteSupport.c       |   4 +-
 src/backend/storage/buffer/buf_init.c      |  25 +-
 src/backend/storage/buffer/bufmgr.c        | 149 +++++-
 src/backend/storage/buffer/s_lock.c        |  21 +-
 src/backend/storage/ipc/ipci.c             |   7 +-
 src/backend/storage/ipc/shmem.c            |  23 +-
 src/backend/storage/large_object/inv_api.c |  18 +-
 src/backend/storage/lmgr/Makefile          |   4 +-
 src/backend/storage/lmgr/lmgr.c            | 580 ++++++---------------
 src/backend/storage/lmgr/lock.c            |  49 +-
 src/backend/utils/adt/sets.c               |   8 +-
 src/backend/utils/cache/relcache.c         |  12 +-
 src/backend/utils/time/tqual.c             | 207 +++++++-
 src/include/access/heapam.h                |  16 +-
 src/include/access/hio.h                   |   6 +-
 src/include/access/htup.h                  |   3 +-
 src/include/access/xact.h                  |   4 +-
 src/include/catalog/pg_am.h                |   3 +-
 src/include/catalog/pg_class.h             |   7 +-
 src/include/commands/trigger.h             |   9 +-
 src/include/storage/buf_internals.h        |  63 +--
 src/include/storage/bufmgr.h               |  13 +-
 src/include/storage/ipc.h                  |   4 +-
 src/include/storage/lmgr.h                 |  64 +--
 src/include/storage/lock.h                 |  12 +-
 src/include/storage/proc.h                 |   4 +-
 src/include/storage/s_lock.h               |   4 +-
 src/include/utils/tqual.h                  |  35 +-
 65 files changed, 1382 insertions(+), 1273 deletions(-)

diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index a7617842042..ce9ef24c88e 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -104,8 +104,7 @@ gistbuild(Relation heap,
 	Buffer		buffer = InvalidBuffer;
 	bool	   *compvec;
 
-	/* GiSTs only know how to do stupid locking now */
-	RelationSetLockForWrite(index);
+	/* no locking is needed */
 
 	setheapoverride(true);		/* so we can see the new pg_index tuple */
 	initGISTstate(&giststate, index);
@@ -269,7 +268,6 @@ gistbuild(Relation heap,
 
 	/* okay, all heap tuples are indexed */
 	heap_endscan(scan);
-	RelationUnsetLockForWrite(index);
 
 	if (pred != NULL || oldPred != NULL)
 	{
@@ -343,7 +341,12 @@ gistinsert(Relation r, Datum *datum, char *nulls, ItemPointer ht_ctid, Relation
 	itup = index_formtuple(RelationGetDescr(r), datum, nulls);
 	itup->t_tid = *ht_ctid;
 
+	/*
+	 * Notes in ExecUtils:ExecOpenIndices()
+	 *
 	RelationSetLockForWrite(r);
+	 */
+
 	res = gistdoinsert(r, itup, &giststate);
 	for (i = 0; i < r->rd_att->natts; i++)
 		if (compvec[i] == TRUE)
@@ -351,7 +354,6 @@ gistinsert(Relation r, Datum *datum, char *nulls, ItemPointer ht_ctid, Relation
 	pfree(itup);
 	pfree(compvec);
 
-	/* XXX two-phase locking -- don't unlock the relation until EOT */
 	return res;
 }
 
@@ -1103,8 +1105,12 @@ gistdelete(Relation r, ItemPointer tid)
 	Buffer		buf;
 	Page		page;
 
-	/* must write-lock on delete */
+	/*
+	 * Notes in ExecUtils:ExecOpenIndices()
+	 * Also note that only vacuum deletes index tuples now...
+	 *
 	RelationSetLockForWrite(r);
+	 */
 
 	blkno = ItemPointerGetBlockNumber(tid);
 	offnum = ItemPointerGetOffsetNumber(tid);
@@ -1120,7 +1126,6 @@ gistdelete(Relation r, ItemPointer tid)
 
 	WriteBuffer(buf);
 
-	/* XXX -- two-phase locking, don't release the write lock */
 }
 
 void
diff --git a/src/backend/access/gist/gistscan.c b/src/backend/access/gist/gistscan.c
index f74316cb331..3528fd30ce2 100644
--- a/src/backend/access/gist/gistscan.c
+++ b/src/backend/access/gist/gistscan.c
@@ -65,7 +65,12 @@ gistbeginscan(Relation r,
 {
 	IndexScanDesc s;
 
+	/*
+	 * Let index_beginscan does its work...
+	 *
 	RelationSetLockForRead(r);
+	 */
+
 	s = RelationGetIndexScan(r, fromEnd, nkeys, key);
 	gistregscan(s);
 
diff --git a/src/backend/access/hash/hashpage.c b/src/backend/access/hash/hashpage.c
index dc3ad3727aa..208cda1bf7e 100644
--- a/src/backend/access/hash/hashpage.c
+++ b/src/backend/access/hash/hashpage.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/hash/hashpage.c,v 1.17 1998/09/01 03:20:58 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/hash/hashpage.c,v 1.18 1998/12/15 12:45:10 vadim Exp $
  *
  * NOTES
  *	  Postgres hash pages look like ordinary relation pages.  The opaque
@@ -81,7 +81,7 @@ _hash_metapinit(Relation rel)
 
 	/* can't be sharing this with anyone, now... */
 	if (USELOCKING)
-		RelationSetLockForWrite(rel);
+		LockRelation(rel, AccessExclusiveLock);
 
 	if ((nblocks = RelationGetNumberOfBlocks(rel)) != 0)
 	{
@@ -169,7 +169,7 @@ _hash_metapinit(Relation rel)
 	_hash_relbuf(rel, metabuf, HASH_WRITE);
 
 	if (USELOCKING)
-		RelationUnsetLockForWrite(rel);
+		UnlockRelation(rel, AccessExclusiveLock);
 }
 
 /*
@@ -316,19 +316,16 @@ _hash_setpagelock(Relation rel,
 				  BlockNumber blkno,
 				  int access)
 {
-	ItemPointerData iptr;
 
 	if (USELOCKING)
 	{
-		ItemPointerSet(&iptr, blkno, 1);
-
 		switch (access)
 		{
 			case HASH_WRITE:
-				RelationSetSingleWLockPage(rel, &iptr);
+				LockPage(rel, blkno, ExclusiveLock);
 				break;
 			case HASH_READ:
-				RelationSetSingleRLockPage(rel, &iptr);
+				LockPage(rel, blkno, ShareLock);
 				break;
 			default:
 				elog(ERROR, "_hash_setpagelock: invalid access (%d) on blk %x: %s",
@@ -343,19 +340,16 @@ _hash_unsetpagelock(Relation rel,
 					BlockNumber blkno,
 					int access)
 {
-	ItemPointerData iptr;
 
 	if (USELOCKING)
 	{
-		ItemPointerSet(&iptr, blkno, 1);
-
 		switch (access)
 		{
 			case HASH_WRITE:
-				RelationUnsetSingleWLockPage(rel, &iptr);
+				UnlockPage(rel, blkno, ExclusiveLock);
 				break;
 			case HASH_READ:
-				RelationUnsetSingleRLockPage(rel, &iptr);
+				UnlockPage(rel, blkno, ShareLock);
 				break;
 			default:
 				elog(ERROR, "_hash_unsetpagelock: invalid access (%d) on blk %x: %s",
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 76fcfaf2c82..8ffd9d41922 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.38 1998/11/27 19:51:36 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.39 1998/12/15 12:45:13 vadim Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -89,15 +89,12 @@
 #include <utils/inval.h>
 #include <utils/memutils.h>
 
-
 #ifndef HAVE_MEMMOVE
 #include <regex/utils.h>
 #else
 #include <string.h>
 #endif
 
-static void doinsert(Relation relation, HeapTuple tup);
-
 /* ----------------------------------------------------------------
  *						 heap support routines
  * ----------------------------------------------------------------
@@ -214,7 +211,7 @@ static void
 heapgettup(Relation relation,
 		   HeapTuple tuple,
 		   int dir,
-		   Buffer *buf,
+		   Buffer *buffer,
 		   Snapshot snapshot,
 		   int nkeys,
 		   ScanKey key)
@@ -255,7 +252,7 @@ heapgettup(Relation relation,
 		elog(DEBUG, "heapgettup(%s, tid=0x%x, dir=%d, ...)",
 			 RelationGetRelationName(relation), tid, dir);
 	}
-	elog(DEBUG, "heapgettup(..., b=0x%x, nkeys=%d, key=0x%x", buf, nkeys, key);
+	elog(DEBUG, "heapgettup(..., b=0x%x, nkeys=%d, key=0x%x", buffer, nkeys, key);
 
 	elog(DEBUG, "heapgettup: relation(%c)=`%s', %p",
 		 relation->rd_rel->relkind, &relation->rd_rel->relname,
@@ -288,25 +285,26 @@ heapgettup(Relation relation,
 		/* assume it is a valid TID XXX */
 		if (ItemPointerIsValid(tid) == false)
 		{
-			*buf = InvalidBuffer;
+			*buffer = InvalidBuffer;
 			tuple->t_data = NULL;
 			return;
 		}
-		*buf = RelationGetBufferWithBuffer(relation,
+		*buffer = RelationGetBufferWithBuffer(relation,
 										   ItemPointerGetBlockNumber(tid),
-										   *buf);
+										   *buffer);
 
-#ifndef NO_BUFFERISVALID
-		if (!BufferIsValid(*buf))
+		if (!BufferIsValid(*buffer))
 			elog(ERROR, "heapgettup: failed ReadBuffer");
-#endif
 
-		dp = (Page) BufferGetPage(*buf);
+		LockBuffer(*buffer, BUFFER_LOCK_SHARE);
+
+		dp = (Page) BufferGetPage(*buffer);
 		lineoff = ItemPointerGetOffsetNumber(tid);
 		lpp = PageGetItemId(dp, lineoff);
 
 		tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp);
 		tuple->t_len = ItemIdGetLength(lpp);
+		LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
 		return;
 
 	}
@@ -328,18 +326,18 @@ heapgettup(Relation relation,
 		}
 		if (page < 0)
 		{
-			*buf = InvalidBuffer;
+			*buffer = InvalidBuffer;
 			tuple->t_data = NULL;
 			return;
 		}
 
-		*buf = RelationGetBufferWithBuffer(relation, page, *buf);
-#ifndef NO_BUFFERISVALID
-		if (!BufferIsValid(*buf))
+		*buffer = RelationGetBufferWithBuffer(relation, page, *buffer);
+		if (!BufferIsValid(*buffer))
 			elog(ERROR, "heapgettup: failed ReadBuffer");
-#endif
 
-		dp = (Page) BufferGetPage(*buf);
+		LockBuffer(*buffer, BUFFER_LOCK_SHARE);
+
+		dp = (Page) BufferGetPage(*buffer);
 		lines = PageGetMaxOffsetNumber(dp);
 		if (tid == NULL)
 		{
@@ -373,19 +371,19 @@ heapgettup(Relation relation,
 
 		if (page >= pages)
 		{
-			*buf = InvalidBuffer;
+			*buffer = InvalidBuffer;
 			tuple->t_data = NULL;
 			return;
 		}
 		/* page and lineoff now reference the physically next tid */
 
-		*buf = RelationGetBufferWithBuffer(relation, page, *buf);
-#ifndef NO_BUFFERISVALID
-		if (!BufferIsValid(*buf))
+		*buffer = RelationGetBufferWithBuffer(relation, page, *buffer);
+		if (!BufferIsValid(*buffer))
 			elog(ERROR, "heapgettup: failed ReadBuffer");
-#endif
 
-		dp = (Page) BufferGetPage(*buf);
+		LockBuffer(*buffer, BUFFER_LOCK_SHARE);
+
+		dp = (Page) BufferGetPage(*buffer);
 		lines = PageGetMaxOffsetNumber(dp);
 	}
 
@@ -420,10 +418,13 @@ heapgettup(Relation relation,
 				 *	if current tuple qualifies, return it.
 				 * ----------------
 				 */
-				HeapTupleSatisfies(tuple, relation, *buf, (PageHeader) dp,
+				HeapTupleSatisfies(tuple, relation, *buffer, (PageHeader) dp,
 								   snapshot, nkeys, key);
 				if (tuple->t_data != NULL)
+				{
+					LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
 					return;
+				}
 			}
 
 			/* ----------------
@@ -448,6 +449,7 @@ heapgettup(Relation relation,
 		 *	this page and it's time to move to the next..
 		 * ----------------
 		 */
+		LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
 		page = nextpage(page, dir);
 
 		/* ----------------
@@ -456,20 +458,19 @@ heapgettup(Relation relation,
 		 */
 		if (page < 0 || page >= pages)
 		{
-			if (BufferIsValid(*buf))
-				ReleaseBuffer(*buf);
-			*buf = InvalidBuffer;
+			if (BufferIsValid(*buffer))
+				ReleaseBuffer(*buffer);
+			*buffer = InvalidBuffer;
 			tuple->t_data = NULL;
 			return;
 		}
 
-		*buf = ReleaseAndReadBuffer(*buf, relation, page);
+		*buffer = ReleaseAndReadBuffer(*buffer, relation, page);
 
-#ifndef NO_BUFFERISVALID
-		if (!BufferIsValid(*buf))
+		if (!BufferIsValid(*buffer))
 			elog(ERROR, "heapgettup: failed ReadBuffer");
-#endif
-		dp = (Page) BufferGetPage(*buf);
+		LockBuffer(*buffer, BUFFER_LOCK_SHARE);
+		dp = (Page) BufferGetPage(*buffer);
 		lines = PageGetMaxOffsetNumber((Page) dp);
 		linesleft = lines - 1;
 		if (dir < 0)
@@ -485,13 +486,6 @@ heapgettup(Relation relation,
 	}
 }
 
-static void
-doinsert(Relation relation, HeapTuple tup)
-{
-	RelationPutHeapTupleAtEnd(relation, tup);
-	return;
-}
-
 
 /* ----------------------------------------------------------------
  *					 heap access method interface
@@ -599,11 +593,7 @@ heap_beginscan(Relation relation,
 	if (RelationIsValid(relation) == false)
 		elog(ERROR, "heap_beginscan: !RelationIsValid(relation)");
 
-	/* ----------------
-	 * set relation level read lock
-	 * ----------------
-	 */
-	RelationSetLockForRead(relation);
+	LockRelation(relation, AccessShareLock);
 
 	/* XXX someday assert SelfTimeQual if relkind == RELKIND_UNCATALOGED */
 	if (relation->rd_rel->relkind == RELKIND_UNCATALOGED)
@@ -707,13 +697,7 @@ heap_endscan(HeapScanDesc scan)
 	 */
 	RelationDecrementReferenceCount(scan->rs_rd);
 
-	/* ----------------
-	 * Non 2-phase read locks on catalog relations
-	 * ----------------
-	 */
-	if (IsSystemRelationName(RelationGetRelationName(scan->rs_rd)->data))
-
-		RelationUnsetLockForRead(scan->rs_rd);
+	UnlockRelation(scan->rs_rd, AccessShareLock);
 
 	pfree(scan);				/* XXX */
 }
@@ -997,14 +981,6 @@ heap_fetch(Relation relation,
 	IncrHeapAccessStat(local_fetch);
 	IncrHeapAccessStat(global_fetch);
 
-	/*
-	 * Note: This is collosally expensive - does two system calls per
-	 * indexscan tuple fetch.  Not good, and since we should be doing page
-	 * level locking by the scanner anyway, it is commented out.
-	 */
-
-	/* RelationSetLockForTupleRead(relation, tid); */
-
 	/* ----------------
 	 *	get the buffer from the relation descriptor
 	 *	Note that this does a buffer pin.
@@ -1013,13 +989,11 @@ heap_fetch(Relation relation,
 
 	buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
 
-#ifndef NO_BUFFERISVALID
 	if (!BufferIsValid(buffer))
-	{
 		elog(ERROR, "heap_fetch: %s relation: ReadBuffer(%lx) failed",
 			 &relation->rd_rel->relname, (long) tid);
-	}
-#endif
+
+	LockBuffer(buffer, BUFFER_LOCK_SHARE);
 
 	/* ----------------
 	 *	get the item line pointer corresponding to the requested tid
@@ -1047,6 +1021,8 @@ heap_fetch(Relation relation,
 	HeapTupleSatisfies(tuple, relation, buffer, dp,
 					   snapshot, 0, (ScanKey) NULL);
 
+	LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
+
 	if (tuple->t_data == NULL)
 	{
 		ReleaseBuffer(buffer);
@@ -1090,14 +1066,6 @@ heap_insert(Relation relation, HeapTuple tup)
 	IncrHeapAccessStat(local_insert);
 	IncrHeapAccessStat(global_insert);
 
-	/* ----------------
-	 *	set relation level write lock. If this is a "local" relation (not
-	 *	visible to others), we don't need to set a write lock.
-	 * ----------------
-	 */
-	if (!relation->rd_islocal)
-		RelationSetLockForWrite(relation);
-
 	/* ----------------
 	 *	If the object id of this tuple has already been assigned, trust
 	 *	the caller.  There are a couple of ways this can happen.  At initial
@@ -1122,228 +1090,178 @@ heap_insert(Relation relation, HeapTuple tup)
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
 
-	doinsert(relation, tup);
+	RelationPutHeapTupleAtEnd(relation, tup);
 
 	if (IsSystemRelationName(RelationGetRelationName(relation)->data))
 	{
-		RelationUnsetLockForWrite(relation);
-
-		/* ----------------
-		 *		invalidate caches (only works for system relations)
-		 * ----------------
-		 */
 		RelationInvalidateHeapTuple(relation, tup);
 	}
 
 	return tup->t_data->t_oid;
 }
 
-/* ----------------
- *		heap_delete		- delete a tuple
- *
- *		Must decide how to handle errors.
- * ----------------
+/*
+ *	heap_delete		- delete a tuple
  */
 int
-heap_delete(Relation relation, ItemPointer tid)
+heap_delete(Relation relation, ItemPointer tid, ItemPointer ctid)
 {
 	ItemId			lp;
 	HeapTupleData	tp;
 	PageHeader		dp;
-	Buffer			buf;
+	Buffer			buffer;
+	int				result;
 
-	/* ----------------
-	 *	increment access statistics
-	 * ----------------
-	 */
+	/* increment access statistics */
 	IncrHeapAccessStat(local_delete);
 	IncrHeapAccessStat(global_delete);
 
-	/* ----------------
-	 *	sanity check
-	 * ----------------
-	 */
 	Assert(ItemPointerIsValid(tid));
 
-	/* ----------------
-	 *	set relation level write lock
-	 * ----------------
-	 */
-	RelationSetLockForWrite(relation);
-
-	buf = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
+	buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
 
-#ifndef NO_BUFFERISVALID
-	if (!BufferIsValid(buf))
-	{							/* XXX L_SH better ??? */
+	if (!BufferIsValid(buffer))
 		elog(ERROR, "heap_delete: failed ReadBuffer");
-	}
-#endif	 /* NO_BUFFERISVALID */
 
-	dp = (PageHeader) BufferGetPage(buf);
-	lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid));
+	LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
 
-	/*
-	 * Just like test against non-functional updates we try to catch
-	 * non-functional delete attempts.			- vadim 05/05/97
-	 */
+	dp = (PageHeader) BufferGetPage(buffer);
+	lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid));
 	tp.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
 	tp.t_len = ItemIdGetLength(lp);
 	tp.t_self = *tid;
 	
-	if (TupleUpdatedByCurXactAndCmd(&tp))
+l1:
+	result = HeapTupleSatisfiesUpdate(&tp);
+	
+	if (result == HeapTupleInvisible)
 	{
-
-		/*
-		 * Vadim says this is no longer needed 1998/6/15 elog(NOTICE,
-		 * "Non-functional delete, tuple already deleted");
-		 */
-		if (IsSystemRelationName(RelationGetRelationName(relation)->data))
-			RelationUnsetLockForWrite(relation);
-		ReleaseBuffer(buf);
-		return 1;
+		LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
+		ReleaseBuffer(buffer);
+		elog(ERROR, "heap_delete: (am)invalid tid");
 	}
-	/* ----------------
-	 *	check that we're deleteing a valid item
-	 * ----------------
-	 */
-	HeapTupleSatisfies((&tp), relation, buf, dp,
-					   false, 0, (ScanKey) NULL);
-	if (!(tp.t_data))
+	else if (result == HeapTupleBeingUpdated)
 	{
-
-		/* XXX call something else */
-		ReleaseBuffer(buf);
-
-		elog(ERROR, "heap_delete: (am)invalid tid");
+		TransactionId	xwait = tp.t_data->t_xmax;
+
+		/* sleep untill concurrent transaction ends */
+		LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
+		XactLockTableWait(xwait);
+
+		LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
+		if (TransactionIdDidAbort(xwait))
+			goto l1;
+		/* concurrent xact committed */
+		Assert(tp.t_data->t_xmax == xwait);
+		if (!(tp.t_data->t_infomask & HEAP_XMAX_COMMITTED))
+		{
+			tp.t_data->t_infomask |= HEAP_XMAX_COMMITTED;
+			SetBufferCommitInfoNeedsSave(buffer);
+		}
+		/* if tuple was marked for update but not updated... */
+		if (tp.t_data->t_infomask & HEAP_MARKED_FOR_UPDATE)
+			result = HeapTupleMayBeUpdated;
+		else
+			result = HeapTupleUpdated;
+	}
+	if (result != HeapTupleMayBeUpdated)
+	{
+		Assert(result == HeapTupleSelfUpdated || result == HeapTupleUpdated);
+		if (ctid != NULL)
+			*ctid = tp.t_data->t_ctid;
+		LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
+		ReleaseBuffer(buffer);
+		return result;
 	}
 
-	/* ----------------
-	 *	get the tuple and lock tell the buffer manager we want
-	 *	exclusive access to the page
-	 * ----------------
-	 */
-
-	/* ----------------
-	 *	store transaction information of xact deleting the tuple
-	 * ----------------
-	 */
+	/* store transaction information of xact deleting the tuple */
 	TransactionIdStore(GetCurrentTransactionId(), &(tp.t_data->t_xmax));
 	tp.t_data->t_cmax = GetCurrentCommandId();
-	tp.t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED | HEAP_XMAX_INVALID);
+	tp.t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED | 
+							   HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE);
 
-	/* ----------------
-	 *	invalidate caches
-	 * ----------------
-	 */
+	LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
+
+	/* invalidate caches */
 	RelationInvalidateHeapTuple(relation, &tp);
 
-	WriteBuffer(buf);
-	if (IsSystemRelationName(RelationGetRelationName(relation)->data))
-		RelationUnsetLockForWrite(relation);
+	WriteBuffer(buffer);
 
-	return 0;
+	return HeapTupleMayBeUpdated;
 }
 
-/* ----------------
- *		heap_replace	- replace a tuple
- *
- *		Must decide how to handle errors.
- *
- *		Fix arguments, work with indexes.
- *
- *		12/30/93 - modified the return value to be 1 when
- *				   a non-functional update is detected. This
- *				   prevents the calling routine from updating
- *				   indices unnecessarily. -kw
- *
- * ----------------
+/*
+ *	heap_replace	- replace a tuple
  */
 int
-heap_replace(Relation relation, ItemPointer otid, HeapTuple newtup)
+heap_replace(Relation relation, ItemPointer otid, HeapTuple newtup, 
+				ItemPointer ctid)
 {
 	ItemId			lp;
 	HeapTupleData	oldtup;
-	Page			dp;
+	PageHeader		dp;
 	Buffer			buffer;
+	int				result;
 
-	/* ----------------
-	 *	increment access statistics
-	 * ----------------
-	 */
+	/* increment access statistics */
 	IncrHeapAccessStat(local_replace);
 	IncrHeapAccessStat(global_replace);
 
-	/* ----------------
-	 *	sanity checks
-	 * ----------------
-	 */
 	Assert(ItemPointerIsValid(otid));
 
-	/* ----------------
-	 *	set relation level write lock
-	 * ----------------
-	 */
-	if (!relation->rd_islocal)
-		RelationSetLockForWrite(relation);
-
 	buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(otid));
 	if (!BufferIsValid(buffer))
 		elog(ERROR, "amreplace: failed ReadBuffer");
+	LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
 
-	dp = (Page) BufferGetPage(buffer);
+	dp = (PageHeader) BufferGetPage(buffer);
 	lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(otid));
 
-	/* ----------------
-	 *	logically delete old item
-	 * ----------------
-	 */
-
 	oldtup.t_data = (HeapTupleHeader) PageGetItem(dp, lp);
 	oldtup.t_len = ItemIdGetLength(lp);
 	oldtup.t_self = *otid;
 
-	/* -----------------
-	 *	the following test should be able to catch all non-functional
-	 *	update attempts and shut out all ghost tuples.
-	 *	XXX In the future, Spyros may need to update the rule lock on a tuple
-	 *	more than once within the same command and same transaction.
-	 *	He will have to introduce a new flag to override the following check.
-	 *	-- Wei
-	 *
-	 * -----------------
-	 */
-
-	if (TupleUpdatedByCurXactAndCmd(&oldtup))
+l2:
+	result = HeapTupleSatisfiesUpdate(&oldtup);
+	
+	if (result == HeapTupleInvisible)
 	{
-		elog(NOTICE, "Non-functional update, only first update is performed");
-		if (IsSystemRelationName(RelationGetRelationName(relation)->data))
-			RelationUnsetLockForWrite(relation);
+		LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
 		ReleaseBuffer(buffer);
-		return 1;
+		elog(ERROR, "heap_replace: (am)invalid tid");
 	}
-
-	/* ----------------
-	 *	check that we're replacing a valid item -
-	 *
-	 *	NOTE that this check must follow the non-functional update test
-	 *		 above as it can happen that we try to 'replace' the same tuple
-	 *		 twice in a single transaction.  The second time around the
-	 *		 tuple will fail the NowTimeQual.  We don't want to abort the
-	 *		 xact, we only want to flag the 'non-functional' NOTICE. -mer
-	 * ----------------
-	 */
-	HeapTupleSatisfies((&oldtup),
-					   relation,
-					   buffer,
-					   (PageHeader) dp,
-					   false,
-					   0,
-					   (ScanKey) NULL);
-	if (!(oldtup.t_data))
+	else if (result == HeapTupleBeingUpdated)
 	{
+		TransactionId	xwait = oldtup.t_data->t_xmax;
+
+		/* sleep untill concurrent transaction ends */
+		LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
+		XactLockTableWait(xwait);
+
+		LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
+		if (TransactionIdDidAbort(xwait))
+			goto l2;
+		/* concurrent xact committed */
+		Assert(oldtup.t_data->t_xmax == xwait);
+		if (!(oldtup.t_data->t_infomask & HEAP_XMAX_COMMITTED))
+		{
+			oldtup.t_data->t_infomask |= HEAP_XMAX_COMMITTED;
+			SetBufferCommitInfoNeedsSave(buffer);
+		}
+		/* if tuple was marked for update but not updated... */
+		if (oldtup.t_data->t_infomask & HEAP_MARKED_FOR_UPDATE)
+			result = HeapTupleMayBeUpdated;
+		else
+			result = HeapTupleUpdated;
+	}
+	if (result != HeapTupleMayBeUpdated)
+	{
+		Assert(result == HeapTupleSelfUpdated || result == HeapTupleUpdated);
+		if (ctid != NULL)
+			*ctid = oldtup.t_data->t_ctid;
+		LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
 		ReleaseBuffer(buffer);
-		elog(ERROR, "heap_replace: (am)invalid otid");
+		return result;
 	}
 
 	/* XXX order problems if not atomic assignment ??? */
@@ -1354,42 +1272,122 @@ heap_replace(Relation relation, ItemPointer otid, HeapTuple newtup)
 	newtup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	newtup->t_data->t_infomask |= HEAP_XMAX_INVALID;
 
-	/* ----------------
-	 *	insert new item
-	 * ----------------
-	 */
+	/* logically delete old item */
+	TransactionIdStore(GetCurrentTransactionId(), &(oldtup.t_data->t_xmax));
+	oldtup.t_data->t_cmax = GetCurrentCommandId();
+	oldtup.t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED | 
+								   HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE);
+
+	/* insert new item */
 	if ((unsigned) DOUBLEALIGN(newtup->t_len) <= PageGetFreeSpace((Page) dp))
-		RelationPutHeapTuple(relation, BufferGetBlockNumber(buffer), newtup);
+		RelationPutHeapTuple(relation, buffer, newtup);
 	else
 	{
-		/* ----------------
-		 *	new item won't fit on same page as old item, have to look
-		 *	for a new place to put it.
-		 * ----------------
+		/*
+		 * New item won't fit on same page as old item, have to look
+		 * for a new place to put it. Note that we have to unlock
+		 * current buffer context - not good but RelationPutHeapTupleAtEnd
+		 * uses extend lock.
 		 */
-		doinsert(relation, newtup);
+		LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
+		RelationPutHeapTupleAtEnd(relation, newtup);
+		LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
 	}
 
-	/* ----------------
-	 *	new item in place, now record transaction information
-	 * ----------------
+	/*
+	 * New item in place, now record address of new tuple in
+	 * t_ctid of old one.
 	 */
-	TransactionIdStore(GetCurrentTransactionId(), &(oldtup.t_data->t_xmax));
-	oldtup.t_data->t_cmax = GetCurrentCommandId();
-	oldtup.t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED | HEAP_XMAX_INVALID);
+	oldtup.t_data->t_ctid = newtup->t_self;
 
-	/* ----------------
-	 *	invalidate caches
-	 * ----------------
-	 */
+	LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
+
+	/* invalidate caches */
 	RelationInvalidateHeapTuple(relation, &oldtup);
 
 	WriteBuffer(buffer);
 
-	if (IsSystemRelationName(RelationGetRelationName(relation)->data))
-		RelationUnsetLockForWrite(relation);
+	return HeapTupleMayBeUpdated;
+}
+
+/*
+ *	heap_mark4update		- mark a tuple for update
+ */
+int
+heap_mark4update(Relation relation, HeapTuple tuple, Buffer *buffer)
+{
+	ItemPointer		tid = &(tuple->t_self);
+	ItemId			lp;
+	PageHeader		dp;
+	int				result;
+
+	/* increment access statistics */
+	IncrHeapAccessStat(local_mark4update);
+	IncrHeapAccessStat(global_mark4update);
+
+	*buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
+
+	if (!BufferIsValid(*buffer))
+		elog(ERROR, "heap_mark4update: failed ReadBuffer");
+
+	LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
+
+	dp = (PageHeader) BufferGetPage(*buffer);
+	lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid));
+	tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
+	tuple->t_len = ItemIdGetLength(lp);
+	
+l3:
+	result = HeapTupleSatisfiesUpdate(tuple);
+	
+	if (result == HeapTupleInvisible)
+	{
+		LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
+		ReleaseBuffer(*buffer);
+		elog(ERROR, "heap_mark4update: (am)invalid tid");
+	}
+	else if (result == HeapTupleBeingUpdated)
+	{
+		TransactionId	xwait = tuple->t_data->t_xmax;
+
+		/* sleep untill concurrent transaction ends */
+		LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
+		XactLockTableWait(xwait);
+
+		LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
+		if (TransactionIdDidAbort(xwait))
+			goto l3;
+		/* concurrent xact committed */
+		Assert(tuple->t_data->t_xmax == xwait);
+		if (!(tuple->t_data->t_infomask & HEAP_XMAX_COMMITTED))
+		{
+			tuple->t_data->t_infomask |= HEAP_XMAX_COMMITTED;
+			SetBufferCommitInfoNeedsSave(*buffer);
+		}
+		/* if tuple was marked for update but not updated... */
+		if (tuple->t_data->t_infomask & HEAP_MARKED_FOR_UPDATE)
+			result = HeapTupleMayBeUpdated;
+		else
+			result = HeapTupleUpdated;
+	}
+	if (result != HeapTupleMayBeUpdated)
+	{
+		Assert(result == HeapTupleSelfUpdated || result == HeapTupleUpdated);
+		LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
+		return result;
+	}
+
+	/* store transaction information of xact marking the tuple */
+	TransactionIdStore(GetCurrentTransactionId(), &(tuple->t_data->t_xmax));
+	tuple->t_data->t_cmax = GetCurrentCommandId();
+	tuple->t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED | HEAP_XMAX_INVALID);
+	tuple->t_data->t_infomask |= HEAP_MARKED_FOR_UPDATE;
+
+	LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
+
+	WriteNoReleaseBuffer(*buffer);
 
-	return 0;
+	return HeapTupleMayBeUpdated;
 }
 
 /* ----------------
diff --git a/src/backend/access/heap/hio.c b/src/backend/access/heap/hio.c
index 5c727145f6f..462de54ccfd 100644
--- a/src/backend/access/heap/hio.c
+++ b/src/backend/access/heap/hio.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Id: hio.c,v 1.14 1998/11/27 19:51:36 vadim Exp $
+ *	  $Id: hio.c,v 1.15 1998/12/15 12:45:14 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -15,6 +15,7 @@
 #include <postgres.h>
 
 #include <storage/bufpage.h>
+#include <access/hio.h>
 #include <access/heapam.h>
 #include <storage/bufmgr.h>
 #include <utils/memutils.h>
@@ -29,19 +30,20 @@
  *	 Probably needs to have an amdelunique to allow for
  *	 internal index records to be deleted and reordered as needed.
  *	 For the heap AM, this should never be needed.
+ *
+ *	 Note - we assume that caller hold BUFFER_LOCK_EXCLUSIVE on the buffer.
+ *
  */
 void
 RelationPutHeapTuple(Relation relation,
-					 BlockNumber blockIndex,
+					 Buffer buffer,
 					 HeapTuple tuple)
 {
-	Buffer		buffer;
-	Page		pageHeader;
-	BlockNumber numberOfBlocks;
-	OffsetNumber offnum;
-	unsigned int len;
-	ItemId		itemId;
-	Item		item;
+	Page			pageHeader;
+	OffsetNumber	offnum;
+	unsigned int	len;
+	ItemId			itemId;
+	Item			item;
 
 	/* ----------------
 	 *	increment access statistics
@@ -50,21 +52,6 @@ RelationPutHeapTuple(Relation relation,
 	IncrHeapAccessStat(local_RelationPutHeapTuple);
 	IncrHeapAccessStat(global_RelationPutHeapTuple);
 
-	Assert(RelationIsValid(relation));
-	Assert(HeapTupleIsValid(tuple));
-
-	numberOfBlocks = RelationGetNumberOfBlocks(relation);
-	Assert(blockIndex < numberOfBlocks);
-
-	buffer = ReadBuffer(relation, blockIndex);
-#ifndef NO_BUFFERISVALID
-	if (!BufferIsValid(buffer))
-	{
-		elog(ERROR, "RelationPutHeapTuple: no buffer for %ld in %s",
-			 blockIndex, &relation->rd_rel->relname);
-	}
-#endif
-
 	pageHeader = (Page) BufferGetPage(buffer);
 	len = (unsigned) DOUBLEALIGN(tuple->t_len); /* be conservative */
 	Assert((int) len <= PageGetFreeSpace(pageHeader));
@@ -75,11 +62,17 @@ RelationPutHeapTuple(Relation relation,
 	itemId = PageGetItemId((Page) pageHeader, offnum);
 	item = PageGetItem((Page) pageHeader, itemId);
 
-	ItemPointerSet(&((HeapTupleHeader) item)->t_ctid, blockIndex, offnum);
+	ItemPointerSet(&((HeapTupleHeader) item)->t_ctid, 
+					BufferGetBlockNumber(buffer), offnum);
 
+	/*
+	 * Let the caller do this!
+	 *
 	WriteBuffer(buffer);
+	 */
+
 	/* return an accurate tuple */
-	ItemPointerSet(&tuple->t_self, blockIndex, offnum);
+	ItemPointerSet(&tuple->t_self, BufferGetBlockNumber(buffer), offnum);
 }
 
 /*
@@ -99,6 +92,7 @@ RelationPutHeapTuple(Relation relation,
  * RelationGetNumberOfBlocks to be useful.
  *
  * NOTE: This code presumes that we have a write lock on the relation.
+ * Not now - we use extend locking...
  *
  * Also note that this routine probably shouldn't have to exist, and does
  * screw up the call graph rather badly, but we are wasting so much time and
@@ -116,8 +110,8 @@ RelationPutHeapTupleAtEnd(Relation relation, HeapTuple tuple)
 	ItemId		itemId;
 	Item		item;
 
-	Assert(RelationIsValid(relation));
-	Assert(HeapTupleIsValid(tuple));
+	if (!relation->rd_islocal)
+		LockRelation(relation, ExtendLock);
 
 	/*
 	 * XXX This does an lseek - VERY expensive - but at the moment it is
@@ -132,16 +126,18 @@ RelationPutHeapTupleAtEnd(Relation relation, HeapTuple tuple)
 	{
 		buffer = ReadBuffer(relation, lastblock);
 		pageHeader = (Page) BufferGetPage(buffer);
-		if (PageIsNew((PageHeader) pageHeader))
-		{
-			buffer = ReleaseAndReadBuffer(buffer, relation, P_NEW);
-			pageHeader = (Page) BufferGetPage(buffer);
-			PageInit(pageHeader, BufferGetPageSize(buffer), 0);
-		}
+		/*
+		 * There was IF instead of ASSERT here ?!
+		 */
+		Assert(PageIsNew((PageHeader) pageHeader));
+		buffer = ReleaseAndReadBuffer(buffer, relation, P_NEW);
+		pageHeader = (Page) BufferGetPage(buffer);
+		PageInit(pageHeader, BufferGetPageSize(buffer), 0);
 	}
 	else
 		buffer = ReadBuffer(relation, lastblock - 1);
 
+	LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
 	pageHeader = (Page) BufferGetPage(buffer);
 	len = (unsigned) DOUBLEALIGN(tuple->t_len); /* be conservative */
 
@@ -152,7 +148,9 @@ RelationPutHeapTupleAtEnd(Relation relation, HeapTuple tuple)
 
 	if (len > PageGetFreeSpace(pageHeader))
 	{
+		LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
 		buffer = ReleaseAndReadBuffer(buffer, relation, P_NEW);
+		LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
 		pageHeader = (Page) BufferGetPage(buffer);
 		PageInit(pageHeader, BufferGetPageSize(buffer), 0);
 
@@ -160,6 +158,9 @@ RelationPutHeapTupleAtEnd(Relation relation, HeapTuple tuple)
 			elog(ERROR, "Tuple is too big: size %d", len);
 	}
 
+	if (!relation->rd_islocal)
+		UnlockRelation(relation, ExtendLock);
+
 	offnum = PageAddItem((Page) pageHeader, (Item) tuple->t_data,
 						 tuple->t_len, InvalidOffsetNumber, LP_USED);
 
@@ -173,5 +174,7 @@ RelationPutHeapTupleAtEnd(Relation relation, HeapTuple tuple)
 	/* return an accurate tuple */
 	ItemPointerSet(&tuple->t_self, lastblock, offnum);
 
+	LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
 	WriteBuffer(buffer);
+
 }
diff --git a/src/backend/access/heap/stats.c b/src/backend/access/heap/stats.c
index 2bebfd9b0be..d630dedf815 100644
--- a/src/backend/access/heap/stats.c
+++ b/src/backend/access/heap/stats.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/heap/Attic/stats.c,v 1.13 1997/09/08 02:20:31 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/heap/Attic/stats.c,v 1.14 1998/12/15 12:45:15 vadim Exp $
  *
  * NOTES
  *	  initam should be moved someplace else.
@@ -73,6 +73,7 @@ InitHeapAccessStatistics()
 	stats->global_insert = 0;
 	stats->global_delete = 0;
 	stats->global_replace = 0;
+	stats->global_mark4update = 0;
 	stats->global_markpos = 0;
 	stats->global_restrpos = 0;
 	stats->global_BufferGetRelation = 0;
@@ -94,6 +95,7 @@ InitHeapAccessStatistics()
 	stats->local_insert = 0;
 	stats->local_delete = 0;
 	stats->local_replace = 0;
+	stats->local_mark4update = 0;
 	stats->local_markpos = 0;
 	stats->local_restrpos = 0;
 	stats->local_BufferGetRelation = 0;
@@ -157,6 +159,7 @@ ResetHeapAccessStatistics()
 	stats->local_insert = 0;
 	stats->local_delete = 0;
 	stats->local_replace = 0;
+	stats->local_mark4update = 0;
 	stats->local_markpos = 0;
 	stats->local_restrpos = 0;
 	stats->local_BufferGetRelation = 0;
@@ -274,6 +277,9 @@ PrintHeapAccessStatistics(HeapAccessStatistics stats)
 	printf("local/global_replace:                     %6d/%6d\n",
 		   stats->local_replace, stats->global_replace);
 
+	printf("local/global_mark4update:                     %6d/%6d\n",
+		   stats->local_mark4update, stats->global_mark4update);
+
 	printf("local/global_markpos:                     %6d/%6d\n",
 		   stats->local_markpos, stats->global_markpos);
 
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index aa2d9446504..f1516c669b3 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.28 1998/10/02 16:27:43 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.29 1998/12/15 12:45:15 vadim Exp $
  *
  * INTERFACE ROUTINES
  *		index_open		- open an index relation by relationId
@@ -225,7 +225,7 @@ index_beginscan(Relation relation,
 	RELATION_CHECKS;
 	GET_REL_PROCEDURE(beginscan, ambeginscan);
 
-	RelationSetRIntentLock(relation);
+	LockRelation(relation, AccessShareLock);
 
 	scandesc = (IndexScanDesc)
 		fmgr(procedure, relation, scanFromEnd, numberOfKeys, key);
@@ -262,7 +262,7 @@ index_endscan(IndexScanDesc scan)
 
 	fmgr(procedure, scan);
 
-	RelationUnsetRIntentLock(scan->relation);
+	UnlockRelation(scan->relation, AccessShareLock);
 }
 
 /* ----------------
diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c
index 44349cfe3c7..54ea9ed8abd 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.31 1998/11/27 19:51:40 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.32 1998/12/15 12:45:20 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,6 +18,7 @@
 #include <storage/bufpage.h>
 #include <access/nbtree.h>
 #include <access/heapam.h>
+#include <access/xact.h>
 #include <storage/bufmgr.h>
 #include <fmgr.h>
 
@@ -67,6 +68,8 @@ _bt_doinsert(Relation rel, BTItem btitem, bool index_is_unique, Relation heapRel
 
 	/* trade in our read lock for a write lock */
 	_bt_relbuf(rel, buf, BT_READ);
+
+l1:
 	buf = _bt_getbuf(rel, blkno, BT_WRITE);
 
 	/*
@@ -120,9 +123,25 @@ _bt_doinsert(Relation rel, BTItem btitem, bool index_is_unique, Relation heapRel
 			{					/* they're equal */
 				btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offset));
 				htup.t_self = btitem->bti_itup.t_tid;
-				heap_fetch(heapRel, SnapshotSelf, &htup, &buffer);
-				if (htup.t_data	!= NULL)
-				{				/* it is a duplicate */
+				heap_fetch(heapRel, SnapshotDirty, &htup, &buffer);
+				if (htup.t_data	!= NULL)	/* it is a duplicate */
+				{
+					TransactionId xwait = 
+						(TransactionIdIsValid(SnapshotDirty->xmin)) ? 
+						SnapshotDirty->xmin : SnapshotDirty->xmax;
+
+					/*
+					 * If this tuple is being updated by other transaction
+					 * then we have to wait for its commit/abort.
+					 */
+					if (TransactionIdIsValid(xwait))
+					{
+						if (nbuf != InvalidBuffer)
+							_bt_relbuf(rel, nbuf, BT_READ);
+						_bt_relbuf(rel, buf, BT_WRITE);
+						XactLockTableWait(xwait);
+						goto l1;	/* continue from the begin */
+					}
 					elog(ERROR, "Cannot insert a duplicate key into a unique index");
 				}
 				/* htup null so no buffer to release */
diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c
index 223efc5c91e..306f4fa0e93 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.16 1998/09/01 03:21:14 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtpage.c,v 1.17 1998/12/15 12:45:23 vadim Exp $
  *
  *	NOTES
  *	   Postgres btree pages look like ordinary relation pages.	The opaque
@@ -93,7 +93,7 @@ _bt_metapinit(Relation rel)
 
 	/* can't be sharing this with anyone, now... */
 	if (USELOCKING)
-		RelationSetLockForWrite(rel);
+		LockRelation(rel, AccessExclusiveLock);
 
 	if ((nblocks = RelationGetNumberOfBlocks(rel)) != 0)
 	{
@@ -120,7 +120,7 @@ _bt_metapinit(Relation rel)
 
 	/* all done */
 	if (USELOCKING)
-		RelationUnsetLockForWrite(rel);
+		UnlockRelation(rel, AccessExclusiveLock);
 }
 
 #ifdef NOT_USED
@@ -571,32 +571,26 @@ _bt_getstackbuf(Relation rel, BTStack stack, int access)
 static void
 _bt_setpagelock(Relation rel, BlockNumber blkno, int access)
 {
-	ItemPointerData iptr;
 
 	if (USELOCKING)
 	{
-		ItemPointerSet(&iptr, blkno, P_HIKEY);
-
 		if (access == BT_WRITE)
-			RelationSetSingleWLockPage(rel, &iptr);
+			LockPage(rel, blkno, ExclusiveLock);
 		else
-			RelationSetSingleRLockPage(rel, &iptr);
+			LockPage(rel, blkno, ShareLock);
 	}
 }
 
 static void
 _bt_unsetpagelock(Relation rel, BlockNumber blkno, int access)
 {
-	ItemPointerData iptr;
 
 	if (USELOCKING)
 	{
-		ItemPointerSet(&iptr, blkno, P_HIKEY);
-
 		if (access == BT_WRITE)
-			RelationUnsetSingleWLockPage(rel, &iptr);
+			UnlockPage(rel, blkno, ExclusiveLock);
 		else
-			RelationUnsetSingleRLockPage(rel, &iptr);
+			UnlockPage(rel, blkno, ShareLock);
 	}
 }
 
diff --git a/src/backend/access/rtree/rtree.c b/src/backend/access/rtree/rtree.c
index 3a8feda536d..9bf6d90dae1 100644
--- a/src/backend/access/rtree/rtree.c
+++ b/src/backend/access/rtree/rtree.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.29 1998/11/27 19:51:41 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.30 1998/12/15 12:45:25 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -107,9 +107,6 @@ rtbuild(Relation heap,
 
 	initRtstate(&rtState, index);
 
-	/* rtrees only know how to do stupid locking now */
-	RelationSetLockForWrite(index);
-
 	pred = predInfo->pred;
 	oldPred = predInfo->oldPred;
 
@@ -250,7 +247,6 @@ rtbuild(Relation heap,
 
 	/* okay, all heap tuples are indexed */
 	heap_endscan(scan);
-	RelationUnsetLockForWrite(index);
 
 	if (pred != NULL || oldPred != NULL)
 	{
@@ -308,10 +304,14 @@ rtinsert(Relation r, Datum *datum, char *nulls, ItemPointer ht_ctid, Relation he
 	itup->t_tid = *ht_ctid;
 	initRtstate(&rtState, r);
 
+	/*
+	 * Notes in ExecUtils:ExecOpenIndices()
+	 *
 	RelationSetLockForWrite(r);
+	 */
+
 	res = rtdoinsert(r, itup, &rtState);
 
-	/* XXX two-phase locking -- don't unlock the relation until EOT */
 	return res;
 }
 
@@ -946,8 +946,12 @@ rtdelete(Relation r, ItemPointer tid)
 	Buffer		buf;
 	Page		page;
 
-	/* must write-lock on delete */
+	/*
+	 * Notes in ExecUtils:ExecOpenIndices()
+	 * Also note that only vacuum deletes index tuples now...
+	 *
 	RelationSetLockForWrite(r);
+	 */
 
 	blkno = ItemPointerGetBlockNumber(tid);
 	offnum = ItemPointerGetOffsetNumber(tid);
@@ -963,7 +967,6 @@ rtdelete(Relation r, ItemPointer tid)
 
 	WriteBuffer(buf);
 
-	/* XXX -- two-phase locking, don't release the write lock */
 	return (char *) NULL;
 }
 
diff --git a/src/backend/access/rtree/rtscan.c b/src/backend/access/rtree/rtscan.c
index 6d0bb632e7f..f2c7927d273 100644
--- a/src/backend/access/rtree/rtscan.c
+++ b/src/backend/access/rtree/rtscan.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtscan.c,v 1.19 1998/09/01 04:27:12 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtscan.c,v 1.20 1998/12/15 12:45:29 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -66,7 +66,12 @@ rtbeginscan(Relation r,
 {
 	IndexScanDesc s;
 
+	/*
+	 * Let index_beginscan does its work...
+	 *
 	RelationSetLockForRead(r);
+	 */
+
 	s = RelationGetIndexScan(r, fromEnd, nkeys, key);
 	rtregscan(s);
 
diff --git a/src/backend/access/transam/transam.c b/src/backend/access/transam/transam.c
index 5bcce3c2d70..b68b6ab6691 100644
--- a/src/backend/access/transam/transam.c
+++ b/src/backend/access/transam/transam.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/transam/transam.c,v 1.19 1998/09/01 04:27:15 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/transam/transam.c,v 1.20 1998/12/15 12:45:30 vadim Exp $
  *
  * NOTES
  *	  This file contains the high level access-method interface to the
@@ -172,8 +172,12 @@ TransactionLogTest(TransactionId transactionId, /* transaction id to test */
 
 	if (!fail)
 	{
-		TransactionIdStore(transactionId, &cachedTestXid);
-		cachedTestXidStatus = xidstatus;
+		/* must not cache status of running xaction !!! */
+		if (xidstatus != XID_INPROGRESS)
+		{
+			TransactionIdStore(transactionId, &cachedTestXid);
+			cachedTestXidStatus = xidstatus;
+		}
 		return (bool)
 			(status == xidstatus);
 	}
@@ -219,11 +223,14 @@ TransactionLogUpdate(TransactionId transactionId,		/* trans id to update */
 								 status,
 								 &fail);
 
-	/* ----------------
-	 *	 update (invalidate) our single item TransactionLogTest cache.
-	 * ----------------
-	 */
+	/*
+	 * update (invalidate) our single item TransactionLogTest cache.
+	 *
 	if (status != XID_COMMIT)
+	 *
+	 * What's the hell ?! Why != XID_COMMIT ?!
+	 */
+	if (status != XID_INPROGRESS)
 	{
 		TransactionIdStore(transactionId, &cachedTestXid);
 		cachedTestXidStatus = status;
diff --git a/src/backend/access/transam/transsup.c b/src/backend/access/transam/transsup.c
index 6f1b09b5774..edf953384f9 100644
--- a/src/backend/access/transam/transsup.c
+++ b/src/backend/access/transam/transsup.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/transam/Attic/transsup.c,v 1.17 1998/09/01 04:27:16 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/transam/Attic/transsup.c,v 1.18 1998/12/15 12:45:33 vadim Exp $
  *
  * NOTES
  *	  This file contains support functions for the high
@@ -289,18 +289,12 @@ TransBlockNumberGetXidStatus(Relation relation,
 	XidStatus	xstatus;		/* recorded status of xid */
 	bool		localfail;		/* bool used if failP = NULL */
 
-	/* ----------------
-	 *	SOMEDAY place a read lock on the log relation
-	 *	That someday is today 5 Aug 1991 -mer
-	 * ----------------
-	 */
-	RelationSetLockForRead(relation);
-
 	/* ----------------
 	 *	get the page containing the transaction information
 	 * ----------------
 	 */
 	buffer = ReadBuffer(relation, blockNumber);
+	LockBuffer(buffer, BUFFER_LOCK_SHARE);
 	block = BufferGetBlock(buffer);
 
 	/* ----------------
@@ -318,14 +312,9 @@ TransBlockNumberGetXidStatus(Relation relation,
 	 *	release the buffer and return the status
 	 * ----------------
 	 */
+	LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
 	ReleaseBuffer(buffer);
 
-	/* ----------------
-	 *	SOMEDAY release our lock on the log relation
-	 * ----------------
-	 */
-	RelationUnsetLockForRead(relation);
-
 	return
 		xstatus;
 }
@@ -345,19 +334,12 @@ TransBlockNumberSetXidStatus(Relation relation,
 	Block		block;			/* block containing xstatus */
 	bool		localfail;		/* bool used if failP = NULL */
 
-	/* ----------------
-	 *	SOMEDAY gain exclusive access to the log relation
-	 *
-	 *	That someday is today 5 Aug 1991 -mer
-	 * ----------------
-	 */
-	RelationSetLockForWrite(relation);
-
 	/* ----------------
 	 *	get the block containing the transaction status
 	 * ----------------
 	 */
 	buffer = ReadBuffer(relation, blockNumber);
+	LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
 	block = BufferGetBlock(buffer);
 
 	/* ----------------
@@ -372,16 +354,11 @@ TransBlockNumberSetXidStatus(Relation relation,
 
 	TransBlockSetXidStatus(block, xid, xstatus);
 
+	LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
 	if ((*failP) == false)
 		WriteBuffer(buffer);
 	else
 		ReleaseBuffer(buffer);
-
-	/* ----------------
-	 *	SOMEDAY release our lock on the log relation
-	 * ----------------
-	 */
-	RelationUnsetLockForWrite(relation);
 }
 
 /* --------------------------------
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 35bcbfed6a4..002b43cd040 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.25 1998/10/08 18:29:15 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.26 1998/12/15 12:45:35 vadim Exp $
  *
  * NOTES
  *		Transaction aborts can now occur two ways:
@@ -194,6 +194,8 @@ TransactionStateData CurrentTransactionStateData = {
 TransactionState CurrentTransactionState =
 &CurrentTransactionStateData;
 
+int	XactIsoLevel = XACT_SERIALIZED;
+
 /* ----------------
  *		info returned when the system is disabled
  *
@@ -816,6 +818,8 @@ StartTransaction()
 	 */
 	GetNewTransactionId(&(s->transactionIdData));
 
+	XactLockTableInsert(s->transactionIdData);
+
 	/* ----------------
 	 *	initialize current transaction state fields
 	 * ----------------
@@ -966,6 +970,7 @@ AbortTransaction()
 	 *	do abort processing
 	 * ----------------
 	 */
+	UnlockBuffers();
 	AtAbort_Notify();
 	CloseSequences();
 	AtEOXact_portals();
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 6c4fb244571..b9057176307 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.17 1998/11/27 19:51:46 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.18 1998/12/15 12:45:39 vadim Exp $
  *
  * NOTES
  *	  See acl.h.
@@ -162,7 +162,7 @@ ChangeAcl(char *relname,
 	tuple = heap_modifytuple(tuple, relation, values, nulls, replaces);
 	/* XXX handle index on pg_class? */
 	setheapoverride(true);
-	heap_replace(relation, &tuple->t_self, tuple);
+	heap_replace(relation, &tuple->t_self, tuple, NULL);
 	setheapoverride(false);
 
 	/* keep the catalog indices up to date */
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 3fbdcec4e32..bc897c5965c 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.69 1998/12/14 05:18:37 scrappy Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.70 1998/12/15 12:45:40 vadim Exp $
  *
  * INTERFACE ROUTINES
  *		heap_create()			- Create an uncataloged heap relation
@@ -929,7 +929,7 @@ RelationRemoveInheritance(Relation relation)
 
 	while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
 	{
-		heap_delete(catalogRelation, &tuple->t_self);
+		heap_delete(catalogRelation, &tuple->t_self, NULL);
 		found = true;
 	}
 
@@ -951,7 +951,7 @@ RelationRemoveInheritance(Relation relation)
 						  &entry);
 
 	while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
-		heap_delete(catalogRelation, &tuple->t_self);
+		heap_delete(catalogRelation, &tuple->t_self, NULL);
 
 	heap_endscan(scan);
 	heap_close(catalogRelation);
@@ -1020,7 +1020,7 @@ DeletePgRelationTuple(Relation rel)
 	 *	delete the relation tuple from pg_class, and finish up.
 	 * ----------------
 	 */
-	heap_delete(pg_class_desc, &tup->t_self);
+	heap_delete(pg_class_desc, &tup->t_self, NULL);
 	pfree(tup);
 
 	heap_close(pg_class_desc);
@@ -1048,7 +1048,7 @@ DeletePgAttributeTuples(Relation rel)
 	 * Get a write lock _before_ getting the read lock in the scan
 	 * ----------------
 	 */
-	RelationSetLockForWrite(pg_attribute_desc);
+	LockRelation(pg_attribute_desc, AccessExclusiveLock);
 
 	for (attnum = FirstLowInvalidHeapAttributeNumber + 1;
 		 attnum <= rel->rd_att->natts;
@@ -1059,7 +1059,7 @@ DeletePgAttributeTuples(Relation rel)
 												   Int16GetDatum(attnum),
 														   0, 0)))
 		{
-			heap_delete(pg_attribute_desc, &tup->t_self);
+			heap_delete(pg_attribute_desc, &tup->t_self, NULL);
 			pfree(tup);
 		}
 	}
@@ -1068,7 +1068,7 @@ DeletePgAttributeTuples(Relation rel)
 	 * Release the write lock
 	 * ----------------
 	 */
-	RelationUnsetLockForWrite(pg_attribute_desc);
+	UnlockRelation(pg_attribute_desc, AccessExclusiveLock);
 	heap_close(pg_attribute_desc);
 }
 
@@ -1183,7 +1183,7 @@ DeletePgTypeTuple(Relation rel)
 	 *	we release the read lock on pg_type.  -mer 13 Aug 1991
 	 * ----------------
 	 */
-	heap_delete(pg_type_desc, &tup->t_self);
+	heap_delete(pg_type_desc, &tup->t_self, NULL);
 
 	heap_endscan(pg_type_scan);
 	heap_close(pg_type_desc);
@@ -1209,7 +1209,7 @@ heap_destroy_with_catalog(char *relname)
 	if (rel == NULL)
 		elog(ERROR, "Relation %s Does Not Exist!", relname);
 
-	RelationSetLockForWrite(rel);
+	LockRelation(rel, AccessExclusiveLock);
 	rid = rel->rd_id;
 
 	/* ----------------
@@ -1288,7 +1288,7 @@ heap_destroy_with_catalog(char *relname)
 
 	rel->rd_tmpunlinked = TRUE;
 
-	RelationUnsetLockForWrite(rel);
+	UnlockRelation(rel, AccessExclusiveLock);
 
 	heap_close(rel);
 
@@ -1608,16 +1608,16 @@ RemoveAttrDefault(Relation rel)
 	ScanKeyEntryInitialize(&key, 0, Anum_pg_attrdef_adrelid,
 						   F_OIDEQ, rel->rd_id);
 
-	RelationSetLockForWrite(adrel);
+	LockRelation(adrel, AccessExclusiveLock);
 
 	adscan = heap_beginscan(adrel, 0, SnapshotNow, 1, &key);
 
 	while (HeapTupleIsValid(tup = heap_getnext(adscan, 0)))
-		heap_delete(adrel, &tup->t_self);
+		heap_delete(adrel, &tup->t_self, NULL);
 
 	heap_endscan(adscan);
 
-	RelationUnsetLockForWrite(adrel);
+	UnlockRelation(adrel, AccessExclusiveLock);
 	heap_close(adrel);
 
 }
@@ -1635,16 +1635,16 @@ RemoveRelCheck(Relation rel)
 	ScanKeyEntryInitialize(&key, 0, Anum_pg_relcheck_rcrelid,
 						   F_OIDEQ, rel->rd_id);
 
-	RelationSetLockForWrite(rcrel);
+	LockRelation(rcrel, AccessExclusiveLock);
 
 	rcscan = heap_beginscan(rcrel, 0, SnapshotNow, 1, &key);
 
 	while (HeapTupleIsValid(tup = heap_getnext(rcscan, 0)))
-		heap_delete(rcrel, &tup->t_self);
+		heap_delete(rcrel, &tup->t_self, NULL);
 
 	heap_endscan(rcscan);
 
-	RelationUnsetLockForWrite(rcrel);
+	UnlockRelation(rcrel, AccessExclusiveLock);
 	heap_close(rcrel);
 
 }
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 0c487bc2496..29565ba285e 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.65 1998/12/13 04:37:50 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.66 1998/12/15 12:45:43 vadim Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -913,7 +913,7 @@ UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate)
 
 	newtup = heap_modifytuple(tuple, pg_index, values, nulls, replace);
 
-	heap_replace(pg_index, &newtup->t_self, newtup);
+	heap_replace(pg_index, &newtup->t_self, newtup, NULL);
 
 	pfree(newtup);
 	heap_close(pg_index);
@@ -1039,15 +1039,11 @@ index_create(char *heapRelationName,
 
 	heapRelation = heap_open(heapoid);
 
-	/* ----------------
-	 * write lock heap to guarantee exclusive access
-	 * ----------------
-	RelationSetLockForWrite(heapRelation);
-	 *				  ^^^^^
-	 * Does it have any sense ?		- vadim 10/27/97
+	/*
+	 * Only SELECT ... FOR UPDATE are allowed
 	 */
 
-	RelationSetLockForRead(heapRelation);
+	LockRelation(heapRelation, ShareLock);
 
 	/* ----------------
 	 *	  construct new tuple descriptor
@@ -1195,7 +1191,7 @@ index_destroy(Oid indexId)
 
 	AssertState(HeapTupleIsValid(tuple));
 
-	heap_delete(relationRelation, &tuple->t_self);
+	heap_delete(relationRelation, &tuple->t_self, NULL);
 	pfree(tuple);
 	heap_close(relationRelation);
 
@@ -1212,7 +1208,7 @@ index_destroy(Oid indexId)
 												   Int16GetDatum(attnum),
 															0, 0)))
 	{
-		heap_delete(attributeRelation, &tuple->t_self);
+		heap_delete(attributeRelation, &tuple->t_self, NULL);
 		pfree(tuple);
 		attnum++;
 	}
@@ -1232,7 +1228,7 @@ index_destroy(Oid indexId)
 
 	indexRelation = heap_openr(IndexRelationName);
 
-	heap_delete(indexRelation, &tuple->t_self);
+	heap_delete(indexRelation, &tuple->t_self, NULL);
 	pfree(tuple);
 	heap_close(indexRelation);
 
@@ -1424,7 +1420,7 @@ UpdateStats(Oid relid, long reltuples, bool hasindex)
 		values[Anum_pg_class_relhasindex - 1] = CharGetDatum(hasindex);
 
 		newtup = heap_modifytuple(tuple, pg_class, values, nulls, replace);
-		heap_replace(pg_class, &tuple->t_self, newtup);
+		heap_replace(pg_class, &tuple->t_self, newtup, NULL);
 		CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
 		CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, newtup);
 		CatalogCloseIndices(Num_pg_class_indices, idescs);
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 96fb9ae35f6..40a33fd5b55 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.30 1998/11/27 19:51:50 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.31 1998/12/15 12:45:45 vadim Exp $
  *
  * NOTES
  *	  these routines moved here from commands/define.c and somewhat cleaned up.
@@ -711,7 +711,7 @@ OperatorDef(char *operatorName,
 								   replaces);
 
 			setheapoverride(true);
-			heap_replace(pg_operator_desc, &tup->t_self, tup);
+			heap_replace(pg_operator_desc, &tup->t_self, tup, NULL);
 			setheapoverride(false);
 		}
 		else
@@ -830,7 +830,7 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
 									   replaces);
 
 				setheapoverride(true);
-				heap_replace(pg_operator_desc, &tup->t_self, tup);
+				heap_replace(pg_operator_desc, &tup->t_self, tup, NULL);
 				setheapoverride(false);
 
 			}
@@ -855,7 +855,7 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
 							   replaces);
 
 		setheapoverride(true);
-		heap_replace(pg_operator_desc, &tup->t_self, tup);
+		heap_replace(pg_operator_desc, &tup->t_self, tup, NULL);
 		setheapoverride(false);
 
 		values[Anum_pg_operator_oprcom - 1] = (Datum) NULL;
@@ -884,7 +884,7 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
 							   replaces);
 
 		setheapoverride(true);
-		heap_replace(pg_operator_desc, &tup->t_self, tup);
+		heap_replace(pg_operator_desc, &tup->t_self, tup, NULL);
 		setheapoverride(false);
 	}
 
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index f46bb8f3a2a..f67317defe0 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.31 1998/11/27 19:51:51 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.32 1998/12/15 12:45:47 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -459,7 +459,7 @@ TypeCreate(char *typeName,
 	 * when the heap_insert() or heap_replace() is called.
 	 * -----------------
 	 */
-	RelationSetLockForWrite(pg_type_desc);
+	LockRelation(pg_type_desc, AccessExclusiveLock);
 
 	typeKey[0].sk_argument = PointerGetDatum(typeName);
 	pg_type_scan = heap_beginscan(pg_type_desc,
@@ -484,7 +484,7 @@ TypeCreate(char *typeName,
 							   replaces);
 
 		setheapoverride(true);
-		heap_replace(pg_type_desc, &tup->t_self, tup);
+		heap_replace(pg_type_desc, &tup->t_self, tup, NULL);
 		setheapoverride(false);
 
 		typeObjectId = tup->t_data->t_oid;
@@ -516,7 +516,7 @@ TypeCreate(char *typeName,
 		CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
 		CatalogCloseIndices(Num_pg_type_indices, idescs);
 	}
-	RelationUnsetLockForWrite(pg_type_desc);
+	UnlockRelation(pg_type_desc, AccessExclusiveLock);
 	heap_close(pg_type_desc);
 
 	return typeObjectId;
@@ -561,7 +561,7 @@ TypeRename(char *oldTypeName, char *newTypeName)
 	namestrcpy(&(((Form_pg_type) GETSTRUCT(oldtup))->typname), newTypeName);
 
 	setheapoverride(true);
-	heap_replace(pg_type_desc, &oldtup->t_self, oldtup);
+	heap_replace(pg_type_desc, &oldtup->t_self, oldtup, NULL);
 	setheapoverride(false);
 
 	/* update the system catalog indices */
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 50d4f13cc09..b18941781d4 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -6,7 +6,7 @@
  * Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.42 1998/11/27 19:51:53 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.43 1998/12/15 12:45:50 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -218,7 +218,7 @@ Async_Listen(char *relname, int pid)
 	TPRINTF(TRACE_NOTIFY, "Async_Listen: %s", relname);
 
 	lRel = heap_openr(ListenerRelationName);
-	RelationSetLockForWrite(lRel);
+	LockRelation(lRel, AccessExclusiveLock);
 	tdesc = RelationGetDescr(lRel);
 
 	/* Detect whether we are already listening on this relname */
@@ -242,7 +242,7 @@ Async_Listen(char *relname, int pid)
 	if (alreadyListener)
 	{
 		elog(NOTICE, "Async_Listen: We are already listening on %s", relname);
-		RelationUnsetLockForWrite(lRel);
+		UnlockRelation(lRel, AccessExclusiveLock);
 		heap_close(lRel);
 		return;
 	}
@@ -267,7 +267,7 @@ Async_Listen(char *relname, int pid)
 	heap_insert(lRel, newtup);
 	pfree(newtup);
 
-	RelationUnsetLockForWrite(lRel);
+	UnlockRelation(lRel, AccessExclusiveLock);
 	heap_close(lRel);
 
 	/*
@@ -320,9 +320,9 @@ Async_Unlisten(char *relname, int pid)
 	if (lTuple != NULL)
 	{
 		lRel = heap_openr(ListenerRelationName);
-		RelationSetLockForWrite(lRel);
-		heap_delete(lRel, &lTuple->t_self);
-		RelationUnsetLockForWrite(lRel);
+		LockRelation(lRel, AccessExclusiveLock);
+		heap_delete(lRel, &lTuple->t_self, NULL);
+		UnlockRelation(lRel, AccessExclusiveLock);
 		heap_close(lRel);
 	}
 	/* We do not complain about unlistening something not being listened;
@@ -358,7 +358,7 @@ Async_UnlistenAll()
 	TPRINTF(TRACE_NOTIFY, "Async_UnlistenAll");
 
 	lRel = heap_openr(ListenerRelationName);
-	RelationSetLockForWrite(lRel);
+	LockRelation(lRel, AccessExclusiveLock);
 	tdesc = RelationGetDescr(lRel);
 
 	/* Find and delete all entries with my listenerPID */
@@ -369,10 +369,10 @@ Async_UnlistenAll()
 	sRel = heap_beginscan(lRel, 0, SnapshotNow, 1, key);
 
 	while (HeapTupleIsValid(lTuple = heap_getnext(sRel, 0)))
-		heap_delete(lRel, &lTuple->t_self);
+		heap_delete(lRel, &lTuple->t_self, NULL);
 
 	heap_endscan(sRel);
-	RelationUnsetLockForWrite(lRel);
+	UnlockRelation(lRel, AccessExclusiveLock);
 	heap_close(lRel);
 }
 
@@ -463,7 +463,7 @@ AtCommit_Notify()
 	TPRINTF(TRACE_NOTIFY, "AtCommit_Notify");
 
 	lRel = heap_openr(ListenerRelationName);
-	RelationSetLockForWrite(lRel);
+	LockRelation(lRel, AccessExclusiveLock);
 	tdesc = RelationGetDescr(lRel);
 	sRel = heap_beginscan(lRel, 0, SnapshotNow, 0, (ScanKey) NULL);
 
@@ -516,7 +516,7 @@ AtCommit_Notify()
 					 * but as far as I can see we should just do it for any
 					 * failure (certainly at least for EPERM too...)
 					 */
-					heap_delete(lRel, &lTuple->t_self);
+					heap_delete(lRel, &lTuple->t_self, NULL);
 				}
 				else
 #endif
@@ -527,7 +527,7 @@ AtCommit_Notify()
 					{
 						rTuple = heap_modifytuple(lTuple, lRel,
 												  value, nulls, repl);
-						heap_replace(lRel, &lTuple->t_self, rTuple);
+						heap_replace(lRel, &lTuple->t_self, rTuple, NULL);
 					}
 				}
 			}
@@ -741,7 +741,7 @@ ProcessIncomingNotify(void)
 	StartTransactionCommand();
 
 	lRel = heap_openr(ListenerRelationName);
-	RelationSetLockForWrite(lRel);
+	LockRelation(lRel, AccessExclusiveLock);
 	tdesc = RelationGetDescr(lRel);
 
 	/* Scan only entries with my listenerPID */
@@ -772,7 +772,7 @@ ProcessIncomingNotify(void)
 			NotifyMyFrontEnd(relname, sourcePID);
 			/* Rewrite the tuple with 0 in notification column */
 			rTuple = heap_modifytuple(lTuple, lRel, value, nulls, repl);
-			heap_replace(lRel, &lTuple->t_self, rTuple);
+			heap_replace(lRel, &lTuple->t_self, rTuple, NULL);
 		}
 	}
 	heap_endscan(sRel);
diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c
index 6cbf8b980cb..f1fc29f6f6e 100644
--- a/src/backend/commands/command.c
+++ b/src/backend/commands/command.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.33 1998/11/27 19:51:54 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.34 1998/12/15 12:45:52 vadim Exp $
  *
  * NOTES
  *	  The PortalExecutorHeapMemory crap needs to be eliminated
@@ -482,7 +482,7 @@ PerformAddAttribute(char *relationName,
 	heap_close(attrdesc);
 
 	((Form_pg_class) GETSTRUCT(reltup))->relnatts = maxatts;
-	heap_replace(rel, &reltup->t_self, reltup);
+	heap_replace(rel, &reltup->t_self, reltup, NULL);
 
 	/* keep catalog indices current */
 	CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 419874e5d49..61151ef6aad 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -6,7 +6,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.64 1998/11/27 19:51:54 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.65 1998/12/15 12:45:53 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -777,6 +777,20 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
 		pfree(typmod);
 	}
 	pfree(byval);
+
+	/* comments in execUtils.c */
+	if (has_index)
+	{
+		for (i = 0; i < n_indices; i++)
+		{
+			if (index_rels[i] == NULL)
+				continue;
+			if ((index_rels[i])->rd_rel->relam != BTREE_AM_OID && 
+				(index_rels[i])->rd_rel->relam != HASH_AM_OID)
+				UnlockRelation(index_rels[i], AccessExclusiveLock);
+			index_close(index_rels[i]);
+		}
+	}
 	heap_close(rel);
 }
 
@@ -914,7 +928,14 @@ GetIndexRelations(Oid main_relation_oid,
 	*index_rels = (Relation *) palloc(*n_indices * sizeof(Relation));
 
 	for (i = 0, scan = head; i < *n_indices; i++, scan = scan->next)
+	{
 		(*index_rels)[i] = index_open(scan->index_rel_oid);
+		/* comments in execUtils.c */
+		if ((*index_rels)[i] != NULL && 
+			((*index_rels)[i])->rd_rel->relam != BTREE_AM_OID &&
+			((*index_rels)[i])->rd_rel->relam != HASH_AM_OID)
+			LockRelation((*index_rels)[i], AccessExclusiveLock);
+	}
 
 	for (i = 0, scan = head; i < *n_indices + 1; i++)
 	{
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index d25d430c39c..a774ca1deb1 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.27 1998/12/14 05:18:43 scrappy Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.28 1998/12/15 12:45:55 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -235,7 +235,7 @@ check_permissions(char *command,
 	 * delays when multiple 'createdb's or 'destroydb's are run simult.
 	 * -mer 7/3/91
 	 */
-	RelationSetLockForWrite(dbrel);
+	LockRelation(dbrel, AccessExclusiveLock);
 	dbtup = get_pg_dbtup(command, dbname, dbrel);
 	dbfound = HeapTupleIsValid(dbtup);
 
diff --git a/src/backend/commands/defind.c b/src/backend/commands/defind.c
index c071c2d9fe8..33d069e6517 100644
--- a/src/backend/commands/defind.c
+++ b/src/backend/commands/defind.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/defind.c,v 1.28 1998/11/27 19:51:56 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/defind.c,v 1.29 1998/12/15 12:45:56 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -342,7 +342,7 @@ ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
 	heapRelation = heap_open(relationId);
 	indexRelation = index_open(indexId);
 
-	RelationSetLockForWrite(heapRelation);
+	LockRelation(heapRelation, ShareLock);
 
 	InitIndexStrategy(numberOfAttributes, indexRelation, accessMethodId);
 
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index c8b4e836f02..d95c4efdff7 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -174,7 +174,7 @@ DropProceduralLanguage(DropPLangStmt *stmt)
 	}
 
 	rel = heap_openr(LanguageRelationName);
-	heap_delete(rel, &langTup->t_self);
+	heap_delete(rel, &langTup->t_self, NULL);
 
 	pfree(langTup);
 	heap_close(rel);
diff --git a/src/backend/commands/remove.c b/src/backend/commands/remove.c
index e662e90ec56..e11983ea8e9 100644
--- a/src/backend/commands/remove.c
+++ b/src/backend/commands/remove.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.30 1998/11/27 19:51:57 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.31 1998/12/15 12:45:57 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -102,7 +102,7 @@ RemoveOperator(char *operatorName,		/* operator name */
 			elog(ERROR, "RemoveOperator: operator '%s': permission denied",
 				 operatorName);
 #endif
-		heap_delete(relation, &tup->t_self);
+		heap_delete(relation, &tup->t_self, NULL);
 	}
 	else
 	{
@@ -157,7 +157,7 @@ SingleOpOperatorRemove(Oid typeOid)
 		key[0].sk_attno = attnums[i];
 		scan = heap_beginscan(rel, 0, SnapshotNow, 1, key);
 		while (HeapTupleIsValid(tup = heap_getnext(scan, 0)))
-			heap_delete(rel, &tup->t_self);
+			heap_delete(rel, &tup->t_self, NULL);
 		heap_endscan(scan);
 	}
 	heap_close(rel);
@@ -268,7 +268,7 @@ RemoveType(char *typeName)		/* type name to be removed */
 
 	relation = heap_openr(TypeRelationName);
 	typeOid = tup->t_data->t_oid;
-	heap_delete(relation, &tup->t_self);
+	heap_delete(relation, &tup->t_self, NULL);
 
 	/* Now, Delete the "array of" that type */
 	shadow_type = makeArrayTypeName(typeName);
@@ -282,7 +282,7 @@ RemoveType(char *typeName)		/* type name to be removed */
 	}
 
 	typeOid = tup->t_data->t_oid;
-	heap_delete(relation, &tup->t_self);
+	heap_delete(relation, &tup->t_self, NULL);
 
 	heap_close(relation);
 }
@@ -357,7 +357,7 @@ RemoveFunction(char *functionName,		/* function name to be removed */
 		elog(ERROR, "RemoveFunction: function \"%s\" is built-in", functionName);
 	}
 
-	heap_delete(relation, &tup->t_self);
+	heap_delete(relation, &tup->t_self, NULL);
 
 	heap_close(relation);
 }
@@ -428,7 +428,7 @@ RemoveAggregate(char *aggName, char *aggType)
 				 aggName);
 		}
 	}
-	heap_delete(relation, &tup->t_self);
+	heap_delete(relation, &tup->t_self, NULL);
 
 	heap_close(relation);
 }
diff --git a/src/backend/commands/rename.c b/src/backend/commands/rename.c
index c423da11963..2977d9e79d0 100644
--- a/src/backend/commands/rename.c
+++ b/src/backend/commands/rename.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.18 1998/11/27 19:51:57 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.19 1998/12/15 12:45:58 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -180,7 +180,7 @@ renameatt(char *relname,
 			newattname, NAMEDATALEN);
 
 	attrelation = heap_openr(AttributeRelationName);
-	heap_replace(attrelation, &oldatttup->t_self, oldatttup);
+	heap_replace(attrelation, &oldatttup->t_self, oldatttup, NULL);
 
 	/* keep system catalog indices current */
 	CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, irelations);
@@ -248,7 +248,7 @@ renamerel(char *oldrelname, char *newrelname)
 
 	/* insert fixed rel tuple */
 	relrelation = heap_openr(RelationRelationName);
-	heap_replace(relrelation, &oldreltup->t_self, oldreltup);
+	heap_replace(relrelation, &oldreltup->t_self, oldreltup, NULL);
 
 	/* keep the system catalog indices current */
 	CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, irelations);
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 9edec5a9dc6..e391936cbf8 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -162,7 +162,7 @@ DefineSequence(CreateSeqStmt *seq)
 	rel = heap_openr(seq->seqname);
 	Assert(RelationIsValid(rel));
 
-	RelationSetLockForWrite(rel);
+	LockRelation(rel, AccessExclusiveLock);
 
 	tupDesc = RelationGetDescr(rel);
 
@@ -185,7 +185,7 @@ DefineSequence(CreateSeqStmt *seq)
 	if (WriteBuffer(buf) == STATUS_ERROR)
 		elog(ERROR, "DefineSequence: WriteBuffer failed");
 
-	RelationUnsetLockForWrite(rel);
+	UnlockRelation(rel, AccessExclusiveLock);
 	heap_close(rel);
 
 	return;
@@ -200,7 +200,6 @@ nextval(struct varlena * seqin)
 	SeqTable	elm;
 	Buffer		buf;
 	Form_pg_sequence seq;
-	ItemPointerData iptr;
 	int4		incby,
 				maxv,
 				minv,
@@ -209,7 +208,7 @@ nextval(struct varlena * seqin)
 				next,
 				rescnt = 0;
 
-	/* open and WIntentLock sequence */
+	/* open and AccessShareLock sequence */
 	elm = init_sequence("nextval", seqname);
 	pfree(seqname);
 
@@ -219,7 +218,7 @@ nextval(struct varlena * seqin)
 		return elm->last;
 	}
 
-	seq = read_info("nextval", elm, &buf);		/* lock page and read
+	seq = read_info("nextval", elm, &buf);		/* lock page' buffer and read
 												 * tuple */
 
 	next = result = seq->last_value;
@@ -282,12 +281,11 @@ nextval(struct varlena * seqin)
 	seq->last_value = next;		/* last fetched number */
 	seq->is_called = 't';
 
+	LockBuffer(buf, BUFFER_LOCK_UNLOCK);
+
 	if (WriteBuffer(buf) == STATUS_ERROR)
 		elog(ERROR, "%s.nextval: WriteBuffer failed", elm->name);
 
-	ItemPointerSet(&iptr, 0, FirstOffsetNumber);
-	RelationUnsetSingleWLockPage(elm->rel, &iptr);
-
 	return result;
 
 }
@@ -300,7 +298,7 @@ currval(struct varlena * seqin)
 	SeqTable	elm;
 	int4		result;
 
-	/* open and WIntentLock sequence */
+	/* open and AccessShareLock sequence */
 	elm = init_sequence("currval", seqname);
 	pfree(seqname);
 
@@ -320,7 +318,6 @@ setval(struct varlena * seqin, int4 next)
 	SeqTable	elm;
 	Buffer		buf;
 	Form_pg_sequence seq;
-	ItemPointerData iptr;
 
 #ifndef NO_SECURITY
 	if (pg_aclcheck(seqname, getpgusername(), ACL_WR) != ACLCHECK_OK)
@@ -328,9 +325,9 @@ setval(struct varlena * seqin, int4 next)
 			 seqname, seqname);
 #endif
 
-	/* open and WIntentLock sequence */
+	/* open and AccessShareLock sequence */
 	elm = init_sequence("setval", seqname);
-	seq = read_info("setval", elm, &buf);		/* lock page and read
+	seq = read_info("setval", elm, &buf);		/* lock page' buffer and read
 												 * tuple */
 
 	if (seq->cache_value != 1)
@@ -353,27 +350,22 @@ setval(struct varlena * seqin, int4 next)
 	seq->last_value = next;		/* last fetched number */
 	seq->is_called = 't';
 
+	LockBuffer(buf, BUFFER_LOCK_UNLOCK);
+
 	if (WriteBuffer(buf) == STATUS_ERROR)
 		elog(ERROR, "%s.settval: WriteBuffer failed", seqname);
 
-	ItemPointerSet(&iptr, 0, FirstOffsetNumber);
-	RelationUnsetSingleWLockPage(elm->rel, &iptr);
-
 	return next;
 }
 
 static Form_pg_sequence
 read_info(char *caller, SeqTable elm, Buffer *buf)
 {
-	ItemPointerData iptr;
-	PageHeader	page;
-	ItemId		lp;
+	PageHeader		page;
+	ItemId			lp;
 	HeapTupleData	tuple;
 	sequence_magic *sm;
-	Form_pg_sequence seq;
-
-	ItemPointerSet(&iptr, 0, FirstOffsetNumber);
-	RelationSetSingleWLockPage(elm->rel, &iptr);
+	Form_pg_sequence	seq;
 
 	if (RelationGetNumberOfBlocks(elm->rel) != 1)
 		elog(ERROR, "%s.%s: invalid number of blocks in sequence",
@@ -383,6 +375,8 @@ read_info(char *caller, SeqTable elm, Buffer *buf)
 	if (!BufferIsValid(*buf))
 		elog(ERROR, "%s.%s: ReadBuffer failed", elm->name, caller);
 
+	LockBuffer(*buf, BUFFER_LOCK_EXCLUSIVE);
+
 	page = (PageHeader) BufferGetPage(*buf);
 	sm = (sequence_magic *) PageGetSpecialPointer(page);
 
@@ -439,7 +433,7 @@ init_sequence(char *caller, char *name)
 	if (!RelationIsValid(temp->rel))
 		elog(ERROR, "%s.%s: sequence does not exist", name, caller);
 
-	RelationSetWIntentLock(temp->rel);
+	LockRelation(temp->rel, AccessShareLock);
 
 	if (temp->rel->rd_rel->relkind != RELKIND_SEQUENCE)
 		elog(ERROR, "%s.%s: %s is not sequence !", name, caller, name);
@@ -485,7 +479,7 @@ CloseSequences(void)
 		{
 			rel = elm->rel;
 			elm->rel = (Relation) NULL;
-			RelationUnsetWIntentLock(rel);
+			UnlockRelation(rel, AccessShareLock);
 			heap_close(rel);
 		}
 		elm = elm->next;
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 431a70a6ff9..60d0056930b 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -40,7 +40,7 @@ void		RelationBuildTriggers(Relation relation);
 void		FreeTriggerDesc(Relation relation);
 
 static void DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger);
-static HeapTuple GetTupleForTrigger(Relation relation, ItemPointer tid,
+static HeapTuple GetTupleForTrigger(EState *estate, ItemPointer tid,
 				   bool before);
 
 extern GlobalMemory CacheCxt;
@@ -77,7 +77,7 @@ CreateTrigger(CreateTrigStmt *stmt)
 	if (!RelationIsValid(rel))
 		elog(ERROR, "CreateTrigger: there is no relation %s", stmt->relname);
 
-	RelationSetLockForWrite(rel);
+	LockRelation(rel, AccessExclusiveLock);
 
 	TRIGGER_CLEAR_TYPE(tgtype);
 	if (stmt->before)
@@ -114,7 +114,7 @@ CreateTrigger(CreateTrigStmt *stmt)
 
 	/* Scan pg_trigger */
 	tgrel = heap_openr(TriggerRelationName);
-	RelationSetLockForWrite(tgrel);
+	LockRelation(tgrel, AccessExclusiveLock);
 	ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
 						   F_OIDEQ, RelationGetRelid(rel));
 	tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key);
@@ -211,7 +211,7 @@ CreateTrigger(CreateTrigStmt *stmt)
 	CatalogIndexInsert(idescs, Num_pg_trigger_indices, tgrel, tuple);
 	CatalogCloseIndices(Num_pg_trigger_indices, idescs);
 	pfree(tuple);
-	RelationUnsetLockForWrite(tgrel);
+	UnlockRelation(tgrel, AccessExclusiveLock);
 	heap_close(tgrel);
 
 	pfree(DatumGetPointer(values[Anum_pg_trigger_tgname - 1]));
@@ -227,7 +227,7 @@ CreateTrigger(CreateTrigStmt *stmt)
 	pgrel = heap_openr(RelationRelationName);
 	((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found + 1;
 	RelationInvalidateHeapTuple(pgrel, tuple);
-	heap_replace(pgrel, &tuple->t_self, tuple);
+	heap_replace(pgrel, &tuple->t_self, tuple, NULL);
 	CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
 	CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tuple);
 	CatalogCloseIndices(Num_pg_class_indices, ridescs);
@@ -267,10 +267,10 @@ DropTrigger(DropTrigStmt *stmt)
 	if (!RelationIsValid(rel))
 		elog(ERROR, "DropTrigger: there is no relation %s", stmt->relname);
 
-	RelationSetLockForWrite(rel);
+	LockRelation(rel, AccessExclusiveLock);
 
 	tgrel = heap_openr(TriggerRelationName);
-	RelationSetLockForWrite(tgrel);
+	LockRelation(tgrel, AccessExclusiveLock);
 	ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
 						   F_OIDEQ, RelationGetRelid(rel));
 	tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key);
@@ -280,7 +280,7 @@ DropTrigger(DropTrigStmt *stmt)
 
 		if (namestrcmp(&(pg_trigger->tgname), stmt->trigname) == 0)
 		{
-			heap_delete(tgrel, &tuple->t_self);
+			heap_delete(tgrel, &tuple->t_self, NULL);
 			tgfound++;
 		}
 		else
@@ -293,7 +293,7 @@ DropTrigger(DropTrigStmt *stmt)
 		elog(NOTICE, "DropTrigger: found (and deleted) %d trigger %s on relation %s",
 			 tgfound, stmt->trigname, stmt->relname);
 	heap_endscan(tgscan);
-	RelationUnsetLockForWrite(tgrel);
+	UnlockRelation(tgrel, AccessExclusiveLock);
 	heap_close(tgrel);
 
 	tuple = SearchSysCacheTupleCopy(RELNAME,
@@ -306,7 +306,7 @@ DropTrigger(DropTrigStmt *stmt)
 	pgrel = heap_openr(RelationRelationName);
 	((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found;
 	RelationInvalidateHeapTuple(pgrel, tuple);
-	heap_replace(pgrel, &tuple->t_self, tuple);
+	heap_replace(pgrel, &tuple->t_self, tuple, NULL);
 	CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
 	CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tuple);
 	CatalogCloseIndices(Num_pg_class_indices, ridescs);
@@ -333,17 +333,17 @@ RelationRemoveTriggers(Relation rel)
 	HeapTuple	tup;
 
 	tgrel = heap_openr(TriggerRelationName);
-	RelationSetLockForWrite(tgrel);
+	LockRelation(tgrel, AccessExclusiveLock);
 	ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
 						   F_OIDEQ, RelationGetRelid(rel));
 
 	tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key);
 
 	while (HeapTupleIsValid(tup = heap_getnext(tgscan, 0)))
-		heap_delete(tgrel, &tup->t_self);
+		heap_delete(tgrel, &tup->t_self, NULL);
 
 	heap_endscan(tgscan);
-	RelationUnsetLockForWrite(tgrel);
+	UnlockRelation(tgrel, AccessExclusiveLock);
 	heap_close(tgrel);
 
 }
@@ -376,7 +376,6 @@ RelationBuildTriggers(Relation relation)
 						   ObjectIdGetDatum(RelationGetRelid(relation)));
 
 	tgrel = heap_openr(TriggerRelationName);
-	RelationSetLockForRead(tgrel);
 	irel = index_openr(TriggerRelidIndex);
 	sd = index_beginscan(irel, false, 1, &skey);
 
@@ -450,7 +449,6 @@ RelationBuildTriggers(Relation relation)
 	index_endscan(sd);
 	pfree(sd);
 	index_close(irel);
-	RelationUnsetLockForRead(tgrel);
 	heap_close(tgrel);
 
 	/* Build trigdesc */
@@ -657,16 +655,17 @@ ExecARInsertTriggers(Relation rel, HeapTuple trigtuple)
 }
 
 bool
-ExecBRDeleteTriggers(Relation rel, ItemPointer tupleid)
+ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid)
 {
-	TriggerData *SaveTriggerData;
-	int			ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_DELETE];
-	Trigger   **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_DELETE];
-	HeapTuple	trigtuple;
-	HeapTuple	newtuple = NULL;
-	int			i;
-
-	trigtuple = GetTupleForTrigger(rel, tupleid, true);
+	Relation		rel = estate->es_result_relation_info->ri_RelationDesc;
+	TriggerData	   *SaveTriggerData;
+	int				ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_DELETE];
+	Trigger		  **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_DELETE];
+	HeapTuple		trigtuple;
+	HeapTuple		newtuple = NULL;
+	int				i;
+
+	trigtuple = GetTupleForTrigger(estate, tupleid, true);
 	if (trigtuple == NULL)
 		return false;
 
@@ -692,15 +691,16 @@ ExecBRDeleteTriggers(Relation rel, ItemPointer tupleid)
 }
 
 void
-ExecARDeleteTriggers(Relation rel, ItemPointer tupleid)
+ExecARDeleteTriggers(EState *estate, ItemPointer tupleid)
 {
+	Relation		rel = estate->es_result_relation_info->ri_RelationDesc;
 	TriggerData *SaveTriggerData;
 	int			ntrigs = rel->trigdesc->n_after_row[TRIGGER_EVENT_DELETE];
 	Trigger   **trigger = rel->trigdesc->tg_after_row[TRIGGER_EVENT_DELETE];
 	HeapTuple	trigtuple;
 	int			i;
 
-	trigtuple = GetTupleForTrigger(rel, tupleid, false);
+	trigtuple = GetTupleForTrigger(estate, tupleid, false);
 	Assert(trigtuple != NULL);
 
 	SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData));
@@ -722,17 +722,18 @@ ExecARDeleteTriggers(Relation rel, ItemPointer tupleid)
 }
 
 HeapTuple
-ExecBRUpdateTriggers(Relation rel, ItemPointer tupleid, HeapTuple newtuple)
+ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
 {
-	TriggerData *SaveTriggerData;
-	int			ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE];
-	Trigger   **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_UPDATE];
-	HeapTuple	trigtuple;
-	HeapTuple	oldtuple;
-	HeapTuple	intuple = newtuple;
-	int			i;
-
-	trigtuple = GetTupleForTrigger(rel, tupleid, true);
+	Relation		rel = estate->es_result_relation_info->ri_RelationDesc;
+	TriggerData	   *SaveTriggerData;
+	int				ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE];
+	Trigger		  **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_UPDATE];
+	HeapTuple		trigtuple;
+	HeapTuple		oldtuple;
+	HeapTuple		intuple = newtuple;
+	int				i;
+
+	trigtuple = GetTupleForTrigger(estate, tupleid, true);
 	if (trigtuple == NULL)
 		return NULL;
 
@@ -759,15 +760,16 @@ ExecBRUpdateTriggers(Relation rel, ItemPointer tupleid, HeapTuple newtuple)
 }
 
 void
-ExecARUpdateTriggers(Relation rel, ItemPointer tupleid, HeapTuple newtuple)
+ExecARUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
 {
+	Relation		rel = estate->es_result_relation_info->ri_RelationDesc;
 	TriggerData *SaveTriggerData;
 	int			ntrigs = rel->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE];
 	Trigger   **trigger = rel->trigdesc->tg_after_row[TRIGGER_EVENT_UPDATE];
 	HeapTuple	trigtuple;
 	int			i;
 
-	trigtuple = GetTupleForTrigger(rel, tupleid, false);
+	trigtuple = GetTupleForTrigger(estate, tupleid, false);
 	Assert(trigtuple != NULL);
 
 	SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData));
@@ -789,48 +791,67 @@ ExecARUpdateTriggers(Relation rel, ItemPointer tupleid, HeapTuple newtuple)
 }
 
 static HeapTuple
-GetTupleForTrigger(Relation relation, ItemPointer tid, bool before)
+GetTupleForTrigger(EState *estate, ItemPointer tid, bool before)
 {
-	ItemId			lp;
+	Relation		relation = estate->es_result_relation_info->ri_RelationDesc;
 	HeapTupleData	tuple;
 	HeapTuple		result;
-	PageHeader		dp;
-	Buffer			b;
+	Buffer			buffer;
 
-	b = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
+	if (before)
+	{
+		int		test;
+
+		/*
+		 *	mark tuple for update
+		 */
+		tuple.t_self = *tid;
+		test = heap_mark4update(relation, &tuple, &buffer);
+		switch (test)
+		{
+			case HeapTupleSelfUpdated:
+				ReleaseBuffer(buffer);
+				return(NULL);
 
-	if (!BufferIsValid(b))
-		elog(ERROR, "GetTupleForTrigger: failed ReadBuffer");
+			case HeapTupleMayBeUpdated:
+				break;
 
-	dp = (PageHeader) BufferGetPage(b);
-	lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid));
+			case HeapTupleUpdated:
+				ReleaseBuffer(buffer);
+				if (XactIsoLevel == XACT_SERIALIZED)
+					elog(ERROR, "Serialize access failed due to concurrent update");
+				else
+					elog(ERROR, "Isolation level %u is not supported", XactIsoLevel);
+				return(NULL);
 
-	Assert(ItemIdIsUsed(lp));
+			default:
+				ReleaseBuffer(buffer);
+				elog(ERROR, "Unknown status %u from heap_mark4update", test);
+				return(NULL);
+		}
+	}
+	else
+	{
+		PageHeader		dp;
+		ItemId			lp;
 
-	tuple.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
-	tuple.t_len = ItemIdGetLength(lp);
-	tuple.t_self = *tid;
+		buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
 
-	if (before)
-	{
-		if (TupleUpdatedByCurXactAndCmd(&tuple))
-		{
-			elog(NOTICE, "GetTupleForTrigger: Non-functional delete/update");
-			ReleaseBuffer(b);
-			return NULL;
-		}
+		if (!BufferIsValid(buffer))
+			elog(ERROR, "GetTupleForTrigger: failed ReadBuffer");
 
-		HeapTupleSatisfies(&tuple, relation, b, dp,
-						   false, 0, (ScanKey) NULL);
-		if (!tuple.t_data)
-		{
-			ReleaseBuffer(b);
-			elog(ERROR, "GetTupleForTrigger: (am)invalid tid");
-		}
+		dp = (PageHeader) BufferGetPage(buffer);
+		lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid));
+
+		Assert(ItemIdIsUsed(lp));
+
+		tuple.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
+		tuple.t_len = ItemIdGetLength(lp);
+		tuple.t_self = *tid;
 	}
 
 	result = heap_copytuple(&tuple);
-	ReleaseBuffer(b);
+	ReleaseBuffer(buffer);
 
 	return result;
 }
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index e0c0e51ea13..7c4203528fa 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: user.c,v 1.22 1998/12/14 08:11:00 scrappy Exp $
+ * $Id: user.c,v 1.23 1998/12/15 12:46:00 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -136,7 +136,7 @@ DefineUser(CreateUserStmt *stmt)
 	 * Secure a write lock on pg_shadow so we can be sure of what the next
 	 * usesysid should be.
 	 */
-	RelationSetLockForWrite(pg_shadow_rel);
+	LockRelation(pg_shadow_rel, AccessExclusiveLock);
 
 	scan = heap_beginscan(pg_shadow_rel, false, SnapshotNow, 0, NULL);
 	while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
@@ -154,7 +154,7 @@ DefineUser(CreateUserStmt *stmt)
 
 	if (exists)
 	{
-		RelationUnsetLockForWrite(pg_shadow_rel);
+		UnlockRelation(pg_shadow_rel, AccessExclusiveLock);
 		heap_close(pg_shadow_rel);
 		UserAbortTransactionBlock();
 		elog(ERROR, 
@@ -187,7 +187,7 @@ DefineUser(CreateUserStmt *stmt)
 	 * This goes after the UpdatePgPwdFile to be certain that two backends
 	 * to not attempt to write to the pg_pwd file at the same time.
 	 */
-	RelationUnsetLockForWrite(pg_shadow_rel);
+	UnlockRelation(pg_shadow_rel, AccessExclusiveLock);
 	heap_close(pg_shadow_rel);
 
 	if (IsTransactionBlock() && !inblock)
@@ -235,14 +235,14 @@ AlterUser(AlterUserStmt *stmt)
 	 * dump of the pg_pwd file is done, there is not another backend doing
 	 * the same.
 	 */
-	RelationSetLockForWrite(pg_shadow_rel);
+	LockRelation(pg_shadow_rel, AccessExclusiveLock);
 
 	tuple = SearchSysCacheTuple(USENAME,
 								PointerGetDatum(stmt->user),
 								0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 	{
-		RelationUnsetLockForWrite(pg_shadow_rel);
+		UnlockRelation(pg_shadow_rel, AccessExclusiveLock);
 		heap_close(pg_shadow_rel);
 		UserAbortTransactionBlock();	/* needed? */
 		elog(ERROR, "alterUser: user \"%s\" does not exist", stmt->user);
@@ -288,7 +288,7 @@ AlterUser(AlterUserStmt *stmt)
 
 	UpdatePgPwdFile(sql);
 
-	RelationUnsetLockForWrite(pg_shadow_rel);
+	UnlockRelation(pg_shadow_rel, AccessExclusiveLock);
 	heap_close(pg_shadow_rel);
 
 	if (IsTransactionBlock() && !inblock)
@@ -342,14 +342,14 @@ RemoveUser(char *user)
 	 * dump of the pg_pwd file is done, there is not another backend doing
 	 * the same.
 	 */
-	RelationSetLockForWrite(pg_shadow_rel);
+	LockRelation(pg_shadow_rel, AccessExclusiveLock);
 
 	tuple = SearchSysCacheTuple(USENAME,
 								PointerGetDatum(user),
 								0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 	{
-		RelationUnsetLockForWrite(pg_shadow_rel);
+		UnlockRelation(pg_shadow_rel, AccessExclusiveLock);
 		heap_close(pg_shadow_rel);
 		UserAbortTransactionBlock();
 		elog(ERROR, "removeUser: user \"%s\" does not exist", user);
@@ -422,7 +422,7 @@ RemoveUser(char *user)
 
 	UpdatePgPwdFile(sql);
 
-	RelationUnsetLockForWrite(pg_shadow_rel);
+	UnlockRelation(pg_shadow_rel, AccessExclusiveLock);
 	heap_close(pg_shadow_rel);
 
 	if (IsTransactionBlock() && !inblock)
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index f7bed005add..608dd729ffa 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.91 1998/11/27 19:51:58 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.92 1998/12/15 12:46:01 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -497,7 +497,7 @@ vc_vacone(Oid relid, bool analyze, List *va_cols)
 	}
 
 	/* we require the relation to be locked until the indices are cleaned */
-	RelationSetLockForWrite(onerel);
+	LockRelation(onerel, AccessExclusiveLock);
 
 	/* scan it */
 	vacuum_pages.vpl_num_pages = fraged_pages.vpl_num_pages = 0;
@@ -1918,7 +1918,7 @@ vc_delhilowstats(Oid relid, int attcnt, int *attnums)
 			if (i >= attcnt)
 				continue;		/* don't delete it */
 		}
-		heap_delete(pgstatistic, &tuple->t_self);
+		heap_delete(pgstatistic, &tuple->t_self, NULL);
 	}
 
 	heap_endscan(scan);
@@ -1928,11 +1928,7 @@ vc_delhilowstats(Oid relid, int attcnt, int *attnums)
 static void
 vc_setpagelock(Relation rel, BlockNumber blkno)
 {
-	ItemPointerData itm;
-
-	ItemPointerSet(&itm, blkno, 1);
-
-	RelationSetLockForWritePage(rel, &itm);
+	LockPage(rel, blkno, ExclusiveLock);
 }
 
 /*
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 45be159ae17..712f2285342 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -26,7 +26,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.59 1998/11/27 19:51:59 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.60 1998/12/15 12:46:04 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -51,6 +51,7 @@
 /* #include "access/localam.h" */
 #include "optimizer/var.h"
 #include "access/heapam.h"
+#include "access/xact.h"
 #include "catalog/heap.h"
 #include "commands/trigger.h"
 
@@ -421,7 +422,6 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
 	{
 		/******************
 		 *	  if we have a result relation, open it and
-
 		 *	  initialize the result relation info stuff.
 		 ******************
 		 */
@@ -440,14 +440,7 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
 			elog(ERROR, "You can't change sequence relation %s",
 				 resultRelationDesc->rd_rel->relname.data);
 
-		/*
-		 * Write-lock the result relation right away: if the relation is
-		 * used in a subsequent scan, we won't have to elevate the
-		 * read-lock set by heap_beginscan to a write-lock (needed by
-		 * heap_insert, heap_delete and heap_replace). This will hopefully
-		 * prevent some deadlocks.	- 01/24/94
-		 */
-		RelationSetLockForWrite(resultRelationDesc);
+		LockRelation(resultRelationDesc, RowExclusiveLock);
 
 		resultRelationInfo = makeNode(RelationInfo);
 		resultRelationInfo->ri_RangeTableIndex = resultRelationIndex;
@@ -461,7 +454,8 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
 		 *	in the result relation information..
 		 ******************
 		 */
-		ExecOpenIndices(resultRelationOid, resultRelationInfo);
+		if (operation != CMD_DELETE)
+			ExecOpenIndices(resultRelationOid, resultRelationInfo);
 
 		estate->es_result_relation_info = resultRelationInfo;
 	}
@@ -1006,8 +1000,10 @@ ExecDelete(TupleTableSlot *slot,
 		   ItemPointer tupleid,
 		   EState *estate)
 {
-	RelationInfo *resultRelationInfo;
-	Relation	resultRelationDesc;
+	RelationInfo	   *resultRelationInfo;
+	Relation			resultRelationDesc;
+	ItemPointerData		ctid;
+	int					result;
 
 	/******************
 	 *	get the result relation information
@@ -1022,19 +1018,35 @@ ExecDelete(TupleTableSlot *slot,
 	{
 		bool		dodelete;
 
-		dodelete = ExecBRDeleteTriggers(resultRelationDesc, tupleid);
+		dodelete = ExecBRDeleteTriggers(estate, tupleid);
 
 		if (!dodelete)			/* "do nothing" */
 			return;
 	}
 
-	/******************
+	/*
 	 *	delete the tuple
-	 ******************
 	 */
-	if (heap_delete(resultRelationDesc, /* relation desc */
-					tupleid))	/* item pointer to tuple */
-		return;
+	result = heap_delete(resultRelationDesc, tupleid, &ctid);
+	switch (result)
+	{
+		case HeapTupleSelfUpdated:
+			return;
+
+		case HeapTupleMayBeUpdated:
+			break;
+
+		case HeapTupleUpdated:
+			if (XactIsoLevel == XACT_SERIALIZED)
+				elog(ERROR, "Serialize access failed due to concurrent update");
+			else
+				elog(ERROR, "Isolation level %u is not supported", XactIsoLevel);
+			return;
+
+		default:
+			elog(ERROR, "Unknown status %u from heap_delete", result);
+			return;
+	}
 
 	IncrDeleted();
 	(estate->es_processed)++;
@@ -1054,7 +1066,7 @@ ExecDelete(TupleTableSlot *slot,
 	/* AFTER ROW DELETE Triggers */
 	if (resultRelationDesc->trigdesc &&
 	 resultRelationDesc->trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
-		ExecARDeleteTriggers(resultRelationDesc, tupleid);
+		ExecARDeleteTriggers(estate, tupleid);
 
 }
 
@@ -1075,10 +1087,12 @@ ExecReplace(TupleTableSlot *slot,
 			EState *estate,
 			Query *parseTree)
 {
-	HeapTuple	tuple;
-	RelationInfo *resultRelationInfo;
-	Relation	resultRelationDesc;
-	int			numIndices;
+	HeapTuple			tuple;
+	RelationInfo	   *resultRelationInfo;
+	Relation			resultRelationDesc;
+	ItemPointerData		ctid;
+	int					result;
+	int					numIndices;
 
 	/******************
 	 *	abort the operation if not running transactions
@@ -1117,7 +1131,7 @@ ExecReplace(TupleTableSlot *slot,
 	{
 		HeapTuple	newtuple;
 
-		newtuple = ExecBRUpdateTriggers(resultRelationDesc, tupleid, tuple);
+		newtuple = ExecBRUpdateTriggers(estate, tupleid, tuple);
 
 		if (newtuple == NULL)	/* "do nothing" */
 			return;
@@ -1140,19 +1154,28 @@ ExecReplace(TupleTableSlot *slot,
 		ExecConstraints("ExecReplace", resultRelationDesc, tuple);
 	}
 
-	/******************
+	/*
 	 *	replace the heap tuple
-	 *
-	 * Don't want to continue if our heap_replace didn't actually
-	 * do a replace. This would be the case if heap_replace
-	 * detected a non-functional update. -kw 12/30/93
-	 ******************
 	 */
-	if (heap_replace(resultRelationDesc,		/* relation desc */
-					 tupleid,	/* item ptr of tuple to replace */
-					 tuple))
-	{							/* replacement heap tuple */
-		return;
+	result = heap_replace(resultRelationDesc, tupleid, tuple, &ctid);
+	switch (result)
+	{
+		case HeapTupleSelfUpdated:
+			return;
+
+		case HeapTupleMayBeUpdated:
+			break;
+
+		case HeapTupleUpdated:
+			if (XactIsoLevel == XACT_SERIALIZED)
+				elog(ERROR, "Serialize access failed due to concurrent update");
+			else
+				elog(ERROR, "Isolation level %u is not supported", XactIsoLevel);
+			return;
+
+		default:
+			elog(ERROR, "Unknown status %u from heap_replace", result);
+			return;
 	}
 
 	IncrReplaced();
@@ -1187,7 +1210,7 @@ ExecReplace(TupleTableSlot *slot,
 	/* AFTER ROW UPDATE Triggers */
 	if (resultRelationDesc->trigdesc &&
 	 resultRelationDesc->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0)
-		ExecARUpdateTriggers(resultRelationDesc, tupleid, tuple);
+		ExecARUpdateTriggers(estate, tupleid, tuple);
 }
 
 #if 0
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 1af4fcbc88a..58dbcd19efc 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.40 1998/11/27 19:52:01 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.41 1998/12/15 12:46:05 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -868,7 +868,23 @@ ExecOpenIndices(Oid resultRelationOid,
 			indexOid = lfirsti(indexoid);
 			indexDesc = index_open(indexOid);
 			if (indexDesc != NULL)
+			{
 				relationDescs[i++] = indexDesc;
+				/*
+				 * Hack for not btree and hash indices: they use relation level
+				 * exclusive locking on updation (i.e. - they are not ready 
+				 * for MVCC) and so we have to exclusively lock indices here
+				 * to prevent deadlocks if we will scan them - index_beginscan
+				 * places AccessShareLock, indices update methods don't use 
+				 * locks at all. We release this lock in ExecCloseIndices.
+				 * Note, that hashes use page level locking - i.e. are not
+				 * deadlock-free, - let's them be on their way -:))
+				 *		vadim 03-12-1998
+				 */
+				if (indexDesc->rd_rel->relam != BTREE_AM_OID && 
+						indexDesc->rd_rel->relam != HASH_AM_OID)
+					LockRelation(indexDesc, AccessExclusiveLock);
+			}
 		}
 
 		/* ----------------
@@ -948,9 +964,18 @@ ExecCloseIndices(RelationInfo *resultRelationInfo)
 	relationDescs = resultRelationInfo->ri_IndexRelationDescs;
 
 	for (i = 0; i < numIndices; i++)
-		if (relationDescs[i] != NULL)
-			index_close(relationDescs[i]);
+	{
+		if (relationDescs[i] == NULL)
+			continue;
+		/*
+		 * Notes in ExecOpenIndices.
+		 */
+		if (relationDescs[i]->rd_rel->relam != BTREE_AM_OID && 
+				relationDescs[i]->rd_rel->relam != HASH_AM_OID)
+			UnlockRelation(relationDescs[i], AccessExclusiveLock);
 
+		index_close(relationDescs[i]);
+	}
 	/*
 	 * XXX should free indexInfo array here too.
 	 */
diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c
index 5f528850ffa..5ec45c7c795 100644
--- a/src/backend/executor/nodeHash.c
+++ b/src/backend/executor/nodeHash.c
@@ -6,7 +6,7 @@
  * Copyright (c) 1994, Regents of the University of California
  *
  *
- *  $Id: nodeHash.c,v 1.27 1998/12/14 08:11:02 scrappy Exp $
+ *  $Id: nodeHash.c,v 1.28 1998/12/15 12:46:06 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -693,13 +693,13 @@ ExecScanHashBucket(HashJoinState *hjstate,
 		else
 			heapTuple = (HeapTuple)
 				LONGALIGN(((char *) curtuple + curtuple->t_len + HEAPTUPLESIZE));
-		
-		heapTuple->t_data = (HeapTupleHeader) 
-							((char *) heapTuple + HEAPTUPLESIZE);
 
 		while (heapTuple < (HeapTuple) ABSADDR(bucket->bottom))
 		{
 
+			heapTuple->t_data = (HeapTupleHeader) 
+								((char *) heapTuple + HEAPTUPLESIZE);
+
 			inntuple = ExecStoreTuple(heapTuple,		/* tuple to store */
 									  hjstate->hj_HashTupleSlot,		/* slot */
 									  InvalidBuffer,	/* tuple has no buffer */
@@ -713,8 +713,6 @@ ExecScanHashBucket(HashJoinState *hjstate,
 
 			heapTuple = (HeapTuple)
 				LONGALIGN(((char *) heapTuple + heapTuple->t_len + HEAPTUPLESIZE));
-			heapTuple->t_data = (HeapTupleHeader) 
-								((char *) heapTuple + HEAPTUPLESIZE);
 		}
 
 		if (firstotuple == NULL)
diff --git a/src/backend/parser/gram.c b/src/backend/parser/gram.c
index 6c484aecf18..0eb9d3eb137 100644
--- a/src/backend/parser/gram.c
+++ b/src/backend/parser/gram.c
@@ -235,7 +235,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/Attic/gram.c,v 2.51 1998/12/14 05:18:57 scrappy Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/Attic/gram.c,v 2.52 1998/12/15 12:46:08 vadim Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index c2066a43b12..bc9c9a738a4 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.34 1998/12/13 23:54:40 thomas Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.35 1998/12/15 12:46:14 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1115,7 +1115,6 @@ find_inheritors(Oid relid, Oid **supervec)
 
 
 	inhrel = heap_openr(InheritsRelationName);
-	RelationSetLockForRead(inhrel);
 	inhtupdesc = RelationGetDescr(inhrel);
 
 	/*
@@ -1182,7 +1181,6 @@ find_inheritors(Oid relid, Oid **supervec)
 		}
 	} while (qentry != (SuperQE *) NULL);
 
-	RelationUnsetLockForRead(inhrel);
 	heap_close(inhrel);
 
 	if (nvisited > 0)
diff --git a/src/backend/rewrite/rewriteRemove.c b/src/backend/rewrite/rewriteRemove.c
index fd1472a93cf..8be2f413cfc 100644
--- a/src/backend/rewrite/rewriteRemove.c
+++ b/src/backend/rewrite/rewriteRemove.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v 1.20 1998/12/14 00:02:17 thomas Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v 1.21 1998/12/15 12:46:16 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -127,7 +127,7 @@ RemoveRewriteRule(char *ruleName)
 	/*
 	 * Now delete the tuple...
 	 */
-	heap_delete(RewriteRelation, &tuple->t_self);
+	heap_delete(RewriteRelation, &tuple->t_self, NULL);
 
 	pfree(tuple);
 	heap_close(RewriteRelation);
@@ -164,7 +164,7 @@ RelationRemoveRules(Oid relid)
 							  0, SnapshotNow, 1, &scanKeyData);
 
 	while (HeapTupleIsValid(tuple = heap_getnext(scanDesc, 0)))
-		heap_delete(RewriteRelation, &tuple->t_self);
+		heap_delete(RewriteRelation, &tuple->t_self, NULL);
 
 	heap_endscan(scanDesc);
 	heap_close(RewriteRelation);
diff --git a/src/backend/rewrite/rewriteSupport.c b/src/backend/rewrite/rewriteSupport.c
index 2b57e277116..15a9b18b906 100644
--- a/src/backend/rewrite/rewriteSupport.c
+++ b/src/backend/rewrite/rewriteSupport.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteSupport.c,v 1.29 1998/11/27 19:52:18 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteSupport.c,v 1.30 1998/12/15 12:46:18 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -128,7 +128,7 @@ setRelhasrulesInRelation(Oid relationId, bool relhasrules)
 
 	relationRelation = heap_openr(RelationRelationName);
 	((Form_pg_class) GETSTRUCT(tuple))->relhasrules = relhasrules;
-	heap_replace(relationRelation, &tuple->t_self, tuple);
+	heap_replace(relationRelation, &tuple->t_self, tuple, NULL);
 
 	/* keep the catalog indices up to date */
 	CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c
index 975e999ec2b..620708aaae3 100644
--- a/src/backend/storage/buffer/buf_init.c
+++ b/src/backend/storage/buffer/buf_init.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.19 1998/09/01 04:31:39 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.20 1998/12/15 12:46:18 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -62,13 +62,13 @@ BufferBlock BufferBlocks;
 
 #ifndef HAS_TEST_AND_SET
 long	   *NWaitIOBackendP;
-
 #endif
 
 extern IpcSemaphoreId WaitIOSemId;
 
 long	   *PrivateRefCount;	/* also used in freelist.c */
 long	   *LastRefCount;		/* refcounts of last ExecMain level */
+bits8	   *BufferLocks;		/* */
 long	   *CommitInfoNeedsSave;/* to write buffers where we have filled
 								 * in t_infomask */
 
@@ -146,21 +146,6 @@ InitBufferPool(IPCKey key)
 				foundDescs;
 	int			i;
 
-	/* check padding of BufferDesc and BufferHdr */
-
-	/*
-	 * we need both checks because a sbufdesc_padded >
-	 * PADDED_SBUFDESC_SIZE will shrink sbufdesc to the required size,
-	 * which is bad
-	 */
-	if (sizeof(struct sbufdesc) != PADDED_SBUFDESC_SIZE ||
-		sizeof(struct sbufdesc_unpadded) > PADDED_SBUFDESC_SIZE)
-		elog(ERROR, "Internal error:  sbufdesc does not have the proper size, "
-			 "contact the Postgres developers");
-	if (sizeof(struct sbufdesc_unpadded) <= PADDED_SBUFDESC_SIZE / 2)
-		elog(ERROR, "Internal error:  sbufdesc is greatly over-sized, "
-			 "contact the Postgres developers");
-
 	Data_Descriptors = NBuffers;
 	Free_List_Descriptor = Data_Descriptors;
 	Lookup_List_Descriptor = Data_Descriptors + 1;
@@ -232,6 +217,7 @@ InitBufferPool(IPCKey key)
 			buf->buf_id = i;
 #ifdef HAS_TEST_AND_SET
 			S_INIT_LOCK(&(buf->io_in_progress_lock));
+			S_INIT_LOCK(&(buf->cntx_lock));
 #endif
 		}
 
@@ -252,10 +238,15 @@ InitBufferPool(IPCKey key)
 
 		WaitIOSemId = IpcSemaphoreCreate(IPCKeyGetWaitIOSemaphoreKey(key),
 										 1, IPCProtection, 0, 1, &status);
+		WaitCLSemId = IpcSemaphoreCreate(IPCKeyGetWaitCLSemaphoreKey(key),
+										 1, IPCProtection, 
+										 IpcSemaphoreDefaultStartValue, 
+										 1, &status);
 	}
 #endif
 	PrivateRefCount = (long *) calloc(NBuffers, sizeof(long));
 	LastRefCount = (long *) calloc(NBuffers, sizeof(long));
+	BufferLocks = (bits8*) calloc (NBuffers, sizeof(bits8));
 	CommitInfoNeedsSave = (long *) calloc(NBuffers, sizeof(long));
 }
 
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index cab1e8084e0..d5fa26b6035 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.44 1998/10/08 18:29:54 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.45 1998/12/15 12:46:19 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -86,7 +86,6 @@ static void WaitIO(BufferDesc *buf, SPINLOCK spinlock);
 #ifndef HAS_TEST_AND_SET
 static void SignalIO(BufferDesc *buf);
 extern long *NWaitIOBackendP;	/* defined in buf_init.c */
-
 #endif	 /* HAS_TEST_AND_SET */
 
 static Buffer ReadBufferWithBufferLock(Relation relation, BlockNumber blockNum,
@@ -583,7 +582,6 @@ BufferAlloc(Relation reln,
 					if (buf->refcount > 1)
 						SignalIO(buf);
 #endif	 /* !HAS_TEST_AND_SET */
-
 					/* give up the buffer since we don't need it any more */
 					buf->refcount--;
 					PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] = 0;
@@ -1096,6 +1094,7 @@ WaitIO(BufferDesc *buf, SPINLOCK spinlock)
 
 #else							/* HAS_TEST_AND_SET */
 IpcSemaphoreId WaitIOSemId;
+IpcSemaphoreId WaitCLSemId;
 
 static void
 WaitIO(BufferDesc *buf, SPINLOCK spinlock)
@@ -1933,3 +1932,147 @@ SetBufferCommitInfoNeedsSave(Buffer buffer)
 	if (!BufferIsLocal(buffer))
 		CommitInfoNeedsSave[buffer - 1]++;
 }
+
+void
+UnlockBuffers()
+{
+	BufferDesc *buf;
+	int			i;
+
+	for (i = 0; i < NBuffers; i++)
+	{
+		if (BufferLocks[i] == 0)
+			continue;
+		
+		Assert(BufferIsValid(i+1));
+		buf = &(BufferDescriptors[i]);
+
+#ifdef HAS_TEST_AND_SET
+		S_LOCK(&(buf->cntx_lock));
+#else
+		IpcSemaphoreLock(WaitCLSemId, 0, IpcExclusiveLock);
+#endif
+
+		if (BufferLocks[i] & BL_R_LOCK)
+		{
+			Assert(buf->r_locks > 0);
+			(buf->r_locks)--;
+		}
+		if (BufferLocks[i] & BL_RI_LOCK)
+		{
+			Assert(buf->ri_lock);
+			buf->ri_lock = false;
+		}
+		if (BufferLocks[i] & BL_W_LOCK)
+		{
+			Assert(buf->w_lock);
+			buf->w_lock = false;
+		}
+#ifdef HAS_TEST_AND_SET
+		S_UNLOCK(&(buf->cntx_lock));
+#else
+		IpcSemaphoreUnlock(WaitCLSemId, 0, IpcExclusiveLock);
+#endif
+		BufferLocks[i] = 0;
+	}
+}
+
+void
+LockBuffer (Buffer buffer, int mode)
+{
+	BufferDesc *buf;
+
+	Assert(BufferIsValid(buffer));
+	if (BufferIsLocal(buffer))
+		return;
+
+	buf = &(BufferDescriptors[buffer-1]);
+
+#ifdef HAS_TEST_AND_SET
+		S_LOCK(&(buf->cntx_lock));
+#else
+		IpcSemaphoreLock(WaitCLSemId, 0, IpcExclusiveLock);
+#endif
+
+	if (mode == BUFFER_LOCK_UNLOCK)
+	{
+		if (BufferLocks[buffer-1] & BL_R_LOCK)
+		{
+			Assert(buf->r_locks > 0);
+			Assert(!(buf->w_lock));
+			Assert(!(BufferLocks[buffer-1] & (BL_W_LOCK | BL_RI_LOCK)))
+			(buf->r_locks)--;
+			BufferLocks[buffer-1] &= ~BL_R_LOCK;
+		}
+		else if (BufferLocks[buffer-1] & BL_W_LOCK)
+		{
+			Assert(buf->w_lock);
+			Assert(buf->r_locks == 0 && !buf->ri_lock);
+			Assert(!(BufferLocks[buffer-1] & (BL_R_LOCK | BL_RI_LOCK)))
+			buf->w_lock = false;
+			BufferLocks[buffer-1] &= ~BL_W_LOCK;
+		}
+		else
+			elog(ERROR, "UNLockBuffer: buffer %u is not locked", buffer);
+	}
+	else if (mode == BUFFER_LOCK_SHARE)
+	{
+		unsigned	i = 0;
+
+		Assert(!(BufferLocks[buffer-1] & (BL_R_LOCK | BL_W_LOCK | BL_RI_LOCK)));
+		while (buf->ri_lock || buf->w_lock)
+		{
+#ifdef HAS_TEST_AND_SET
+			S_UNLOCK(&(buf->cntx_lock));
+			s_lock_sleep(i++);
+			S_LOCK(&(buf->cntx_lock));
+#else
+			IpcSemaphoreUnlock(WaitCLSemId, 0, IpcExclusiveLock);
+			s_lock_sleep(i++)
+			IpcSemaphoreLock(WaitCLSemId, 0, IpcExclusiveLock);
+#endif
+		}
+		(buf->r_locks)++;
+		BufferLocks[buffer-1] |= BL_R_LOCK;
+	}
+	else if (mode == BUFFER_LOCK_EXCLUSIVE)
+	{
+		unsigned	i = 0;
+		
+		Assert(!(BufferLocks[buffer-1] & (BL_R_LOCK | BL_W_LOCK | BL_RI_LOCK)));
+		while (buf->r_locks > 0 || buf->w_lock)
+		{
+			if (buf->r_locks > 3)
+			{
+				if (!(BufferLocks[buffer-1] & BL_RI_LOCK))
+					BufferLocks[buffer-1] |= BL_RI_LOCK;
+				buf->ri_lock = true;
+			}
+#ifdef HAS_TEST_AND_SET
+			S_UNLOCK(&(buf->cntx_lock));
+			s_lock_sleep(i++);
+			S_LOCK(&(buf->cntx_lock));
+#else
+			IpcSemaphoreUnlock(WaitCLSemId, 0, IpcExclusiveLock);
+			s_lock_sleep(i++)
+			IpcSemaphoreLock(WaitCLSemId, 0, IpcExclusiveLock);
+#endif
+		}
+		buf->w_lock = true;
+		BufferLocks[buffer-1] |= BL_W_LOCK;
+		if (BufferLocks[buffer-1] & BL_RI_LOCK)
+		{
+			buf->ri_lock = false;
+			BufferLocks[buffer-1] &= ~BL_RI_LOCK;
+		}
+	}
+	else
+		elog(ERROR, "LockBuffer: unknown lock mode %d", mode);
+
+#ifdef HAS_TEST_AND_SET
+		S_UNLOCK(&(buf->cntx_lock));
+#else
+		IpcSemaphoreUnlock(WaitCLSemId, 0, IpcExclusiveLock);
+#endif
+
+}
diff --git a/src/backend/storage/buffer/s_lock.c b/src/backend/storage/buffer/s_lock.c
index a7b42bc4793..439240a386f 100644
--- a/src/backend/storage/buffer/s_lock.c
+++ b/src/backend/storage/buffer/s_lock.c
@@ -7,13 +7,14 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/Attic/s_lock.c,v 1.12 1998/09/18 17:18:39 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/Attic/s_lock.c,v 1.13 1998/12/15 12:46:21 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include <stdio.h>
 #include <sys/time.h>
+#include <unistd.h>
 
 #include "config.h"
 #include "c.h"
@@ -52,6 +53,16 @@ s_lock_stuck(volatile slock_t *lock, const char *file, const int line)
 }
 
 
+void
+s_lock_sleep(unsigned spin)
+{
+	struct timeval delay;
+
+	delay.tv_sec = 0;
+	delay.tv_usec = s_spincycle[spin % S_NSPINCYCLE];
+	(void) select(0, NULL, NULL, NULL, &delay);
+}
+
 
 /*
  * s_lock(lock) - take a spinlock with backoff
@@ -59,15 +70,11 @@ s_lock_stuck(volatile slock_t *lock, const char *file, const int line)
 void
 s_lock(volatile slock_t *lock, const char *file, const int line)
 {
-	int			spins = 0;
+	unsigned	spins = 0;
 
 	while (TAS(lock))
 	{
-		struct timeval delay;
-
-		delay.tv_sec = 0;
-		delay.tv_usec = s_spincycle[spins % S_NSPINCYCLE];
-		(void) select(0, NULL, NULL, NULL, &delay);
+		s_lock_sleep(spins);
 		if (++spins > S_MAX_BUSY)
 		{
 			/* It's been over a minute...  */
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index f6ce9eda241..47305f3f087 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.16 1998/09/01 03:25:10 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.17 1998/12/15 12:46:24 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,7 +17,6 @@
 #include "postgres.h"
 
 #include "storage/ipc.h"
-#include "storage/multilev.h"
 #include "storage/sinval.h"
 #include "storage/bufmgr.h"
 #include "storage/proc.h"
@@ -92,7 +91,7 @@ CreateSharedMemoryAndSemaphores(IPCKey key)
 	 * ----------------
 	 */
 	InitLocks();
-	if (InitMultiLevelLocks() == INVALID_TABLEID)
+	if (InitLockTable() == INVALID_TABLEID)
 		elog(FATAL, "Couldn't create the lock table");
 
 	/* ----------------
@@ -145,7 +144,7 @@ AttachSharedMemoryAndSemaphores(IPCKey key)
 	 * ----------------
 	 */
 	InitLocks();
-	if (InitMultiLevelLocks() == INVALID_TABLEID)
+	if (InitLockTable() == INVALID_TABLEID)
 		elog(FATAL, "Couldn't attach to the lock table");
 
 	AttachSharedInvalidationState(key);
diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index 18b8d718d67..17416fc9eef 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.31 1998/09/01 04:31:49 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.32 1998/12/15 12:46:24 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -68,7 +68,8 @@
 #include "utils/dynahash.h"
 #include "utils/hsearch.h"
 #include "utils/memutils.h"
-#include "access/transam.h"
+#include "access/xact.h"
+#include "utils/tqual.h"
 
 /* shared memory global variables */
 
@@ -629,7 +630,6 @@ TransactionIdIsInProgress(TransactionId xid)
 	return false;
 }
 
-#ifdef LowLevelLocking
 /*
  * GetSnapshotData -- returns information about running transactions.
  *
@@ -645,16 +645,15 @@ Snapshot
 GetSnapshotData(bool serialized)
 {
 	Snapshot	snapshot = (Snapshot) malloc(sizeof(SnapshotData));
-	TransactionId snapshot->xip = (TransactionId *)
-	malloc(32 * sizeof(TransactionId));
 	ShmemIndexEnt *result;
 	PROC	   *proc;
 	TransactionId cid = GetCurrentTransactionId();
-	uint		count = 0;
-	unit		free = 31;
+	uint32		count = 0;
+	uint32		have = 31;
 
 	Assert(ShmemIndex);
 
+	snapshot->xip = (TransactionId *) malloc(32 * sizeof(TransactionId));
 	snapshot->xmax = cid;
 	snapshot->xmin = cid;
 
@@ -676,20 +675,20 @@ GetSnapshotData(bool serialized)
 			continue;
 		proc = (PROC *) MAKE_PTR(result->location);
 		if (proc == MyProc || proc->xid < FirstTransactionId ||
-			serialized && proc->xid >= cid)
+			(serialized && proc->xid >= cid))
 			continue;
 		if (proc->xid < snapshot->xmin)
 			snapshot->xmin = proc->xid;
 		else if (proc->xid > snapshot->xmax)
 			snapshot->xmax = proc->xid;
-		if (free == 0)
+		if (have == 0)
 		{
 			snapshot->xip = (TransactionId *) realloc(snapshot->xip,
 								   (count + 33) * sizeof(TransactionId));
-			free = 32;
+			have = 32;
 		}
 		snapshot->xip[count] = proc->xid;
-		free--;
+		have--;
 		count++;
 	}
 
@@ -699,5 +698,3 @@ GetSnapshotData(bool serialized)
 	elog(ERROR, "GetSnapshotData: ShmemIndex corrupted");
 	return NULL;
 }
-
-#endif
diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c
index 740a4132631..40460404197 100644
--- a/src/backend/storage/large_object/inv_api.c
+++ b/src/backend/storage/large_object/inv_api.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.43 1998/12/13 05:07:50 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.44 1998/12/15 12:46:26 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -203,12 +203,12 @@ inv_create(int flags)
 
 	if (flags & INV_WRITE)
 	{
-		RelationSetLockForWrite(r);
+		LockRelation(r, ExclusiveLock);
 		retval->flags = IFS_WRLOCK | IFS_RDLOCK;
 	}
 	else if (flags & INV_READ)
 	{
-		RelationSetLockForRead(r);
+		LockRelation(r, ShareLock);
 		retval->flags = IFS_RDLOCK;
 	}
 	retval->flags |= IFS_ATEOF;
@@ -254,12 +254,12 @@ inv_open(Oid lobjId, int flags)
 
 	if (flags & INV_WRITE)
 	{
-		RelationSetLockForWrite(r);
+		LockRelation(r, ExclusiveLock);
 		retval->flags = IFS_WRLOCK | IFS_RDLOCK;
 	}
 	else if (flags & INV_READ)
 	{
-		RelationSetLockForRead(r);
+		LockRelation(r, ShareLock);
 		retval->flags = IFS_RDLOCK;
 	}
 
@@ -328,7 +328,7 @@ inv_stat(LargeObjectDesc *obj_desc, struct pgstat * stbuf)
 	/* need read lock for stat */
 	if (!(obj_desc->flags & IFS_RDLOCK))
 	{
-		RelationSetLockForRead(obj_desc->heap_r);
+		LockRelation(obj_desc->heap_r, ShareLock);
 		obj_desc->flags |= IFS_RDLOCK;
 	}
 
@@ -376,7 +376,7 @@ inv_seek(LargeObjectDesc *obj_desc, int offset, int whence)
 		/* need read lock for getsize */
 		if (!(obj_desc->flags & IFS_RDLOCK))
 		{
-			RelationSetLockForRead(obj_desc->heap_r);
+			LockRelation(obj_desc->heap_r, ShareLock);
 			obj_desc->flags |= IFS_RDLOCK;
 		}
 		offset += _inv_getsize(obj_desc->heap_r,
@@ -458,7 +458,7 @@ inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes)
 	/* make sure we obey two-phase locking */
 	if (!(obj_desc->flags & IFS_RDLOCK))
 	{
-		RelationSetLockForRead(obj_desc->heap_r);
+		LockRelation(obj_desc->heap_r, ShareLock);
 		obj_desc->flags |= IFS_RDLOCK;
 	}
 
@@ -516,7 +516,7 @@ inv_write(LargeObjectDesc *obj_desc, char *buf, int nbytes)
 
 	if (!(obj_desc->flags & IFS_WRLOCK))
 	{
-		RelationSetLockForRead(obj_desc->heap_r);
+		LockRelation(obj_desc->heap_r, ShareLock);
 		obj_desc->flags |= (IFS_WRLOCK | IFS_RDLOCK);
 	}
 
diff --git a/src/backend/storage/lmgr/Makefile b/src/backend/storage/lmgr/Makefile
index 66fc25484a4..88cd9d060c4 100644
--- a/src/backend/storage/lmgr/Makefile
+++ b/src/backend/storage/lmgr/Makefile
@@ -4,7 +4,7 @@
 #    Makefile for storage/lmgr
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/backend/storage/lmgr/Makefile,v 1.8 1998/07/26 04:30:40 scrappy Exp $
+#    $Header: /cvsroot/pgsql/src/backend/storage/lmgr/Makefile,v 1.9 1998/12/15 12:46:29 vadim Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -16,7 +16,7 @@ ifdef MULTIBYTE
 CFLAGS+= $(MBFLAGS)
 endif
 
-OBJS = lmgr.o lock.o multi.o proc.o single.o
+OBJS = lmgr.o lock.o proc.o
 
 all: SUBSYS.o
 
diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c
index 13adb8c48f8..307c54e39e1 100644
--- a/src/backend/storage/lmgr/lmgr.c
+++ b/src/backend/storage/lmgr/lmgr.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lmgr.c,v 1.19 1998/09/01 04:31:58 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lmgr.c,v 1.20 1998/12/15 12:46:30 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -49,6 +49,85 @@
 
 extern Oid	MyDatabaseId;
 
+static MASK LockConflicts[] = {
+	(int) NULL,
+
+/* AccessShareLock */
+	(1 << AccessExclusiveLock),
+
+/* RowShareLock */
+	(1 << ExclusiveLock) | (1 << AccessExclusiveLock),
+
+/* RowExclusiveLock */
+	(1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) | (1 << ShareLock) |
+	(1 << AccessExclusiveLock),
+
+/* ShareLock */
+	(1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) |
+	(1 << RowExclusiveLock) | (1 << AccessExclusiveLock),
+
+/* ShareRowExclusiveLock */
+	(1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) |
+	(1 << ShareLock) | (1 << RowExclusiveLock) | (1 << AccessExclusiveLock),
+
+/* ExclusiveLock */
+	(1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) | (1 << ShareLock) |
+	(1 << RowExclusiveLock) | (1 << RowShareLock) | (1 << AccessExclusiveLock),
+
+/* AccessExclusiveLock */
+	(1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) | (1 << ShareLock) |
+	(1 << RowExclusiveLock) | (1 << RowShareLock) | (1 << AccessExclusiveLock) | 
+	(1 << AccessShareLock),
+
+/* ExtendLock */
+	(1 << ExtendLock)
+
+};
+
+static int	LockPrios[] = {
+	(int) NULL,
+	1,
+	2,
+	3,
+	4,
+	5,
+	6,
+	7,
+	1
+};
+
+LOCKMETHOD	LockTableId = (LOCKMETHOD) NULL;
+LOCKMETHOD	LongTermTableId = (LOCKMETHOD) NULL;
+
+/*
+ * Create the lock table described by LockConflicts and LockPrios.
+ */
+LOCKMETHOD
+InitLockTable()
+{
+	int			lockmethod;
+
+	lockmethod = LockMethodTableInit("LockTable",
+						  LockConflicts, LockPrios, MAX_LOCKMODES - 1);
+	LockTableId = lockmethod;
+	if (!(LockTableId))
+		elog(ERROR, "InitLockTable: couldnt initialize lock table");
+
+#ifdef USER_LOCKS
+	/*
+	 * Allocate another tableId for long-term locks
+	 */
+	LongTermTableId = LockMethodTableRename(LockTableId);
+	if (!(LongTermTableId))
+	{
+		elog(ERROR,
+			 "InitLockTable: couldn't rename long-term lock table");
+	}
+#endif
+
+	return LockTableId;
+}
+
 /*
  * RelationInitLockInfo --
  *		Initializes the lock information in a relation descriptor.
@@ -82,130 +161,49 @@ RelationInitLockInfo(Relation relation)
 	else
 		info->lockRelId.dbId = MyDatabaseId;
 
-#ifdef LowLevelLocking
-	memset(info->lockHeld, 0, sizeof(info->lockHeld));
-#endif
-
 	relation->lockInfo = (Pointer) info;
 }
 
 /*
- * RelationSetLockForDescriptorOpen --
- *		Sets read locks for a relation descriptor.
- */
-#ifdef	LOCKDEBUGALL
-#define LOCKDEBUGALL_30 \
-elog(DEBUG, "RelationSetLockForDescriptorOpen(%s[%d,%d]) called", \
-	 RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId)
-#else
-#define LOCKDEBUGALL_30
-#endif	 /* LOCKDEBUGALL */
-
-void
-RelationSetLockForDescriptorOpen(Relation relation)
-{
-	/* ----------------
-	 *	sanity checks
-	 * ----------------
-	 */
-	Assert(RelationIsValid(relation));
-	if (LockingDisabled())
-		return;
-
-	LOCKDEBUGALL_30;
-
-	/* ----------------
-	 * read lock catalog tuples which compose the relation descriptor
-	 * XXX race condition? XXX For now, do nothing.
-	 * ----------------
-	 */
-}
-
-/* ----------------
- *		RelationSetLockForRead
- * ----------------
- */
-#ifdef	LOCKDEBUG
-#define LOCKDEBUG_40 \
-elog(DEBUG, "RelationSetLockForRead(%s[%d,%d]) called", \
-	 RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId)
-#else
-#define LOCKDEBUG_40
-#endif	 /* LOCKDEBUG */
-
-/*
- * RelationSetLockForRead --
- *		Sets relation level read lock.
+ *		LockRelation
  */
 void
-RelationSetLockForRead(Relation relation)
+LockRelation(Relation relation, LOCKMODE lockmode)
 {
 	LockInfo	lockinfo;
+	LOCKTAG		tag;
 
-	/* ----------------
-	 *	sanity checks
-	 * ----------------
-	 */
-	Assert(RelationIsValid(relation));
 	if (LockingDisabled())
 		return;
 
-	LOCKDEBUG_40;
-
-	/* ----------------
-	 * If we don't have lock info on the reln just go ahead and
-	 * lock it without trying to short circuit the lock manager.
-	 * ----------------
-	 */
 	if (!LockInfoIsValid(relation->lockInfo))
-	{
 		RelationInitLockInfo(relation);
-		lockinfo = (LockInfo) relation->lockInfo;
-		MultiLockReln(lockinfo, READ_LOCK);
-		return;
-	}
-	else
-		lockinfo = (LockInfo) relation->lockInfo;
 
-	MultiLockReln(lockinfo, READ_LOCK);
-}
+	lockinfo = (LockInfo) relation->lockInfo;
 
-/* ----------------
- *		RelationUnsetLockForRead
- * ----------------
- */
-#ifdef	LOCKDEBUG
-#define LOCKDEBUG_50 \
-elog(DEBUG, "RelationUnsetLockForRead(%s[%d,%d]) called", \
-	 RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId)
-#else
-#define LOCKDEBUG_50
-#endif	 /* LOCKDEBUG */
+	MemSet(&tag, 0, sizeof(tag));
+	tag.relId = lockinfo->lockRelId.relId;
+	tag.dbId = lockinfo->lockRelId.dbId;
+	tag.objId.blkno = InvalidBlockNumber;
+
+	LockAcquire(LockTableId, &tag, lockmode);
+	return;
+}
 
 /*
- * RelationUnsetLockForRead --
- *		Unsets relation level read lock.
+ *		UnlockRelation
  */
 void
-RelationUnsetLockForRead(Relation relation)
+UnlockRelation(Relation relation, LOCKMODE lockmode)
 {
 	LockInfo	lockinfo;
+	LOCKTAG		tag;
 
-	/* ----------------
-	 *	sanity check
-	 * ----------------
-	 */
-	Assert(RelationIsValid(relation));
 	if (LockingDisabled())
 		return;
 
 	lockinfo = (LockInfo) relation->lockInfo;
 
-	/* ----------------
-	 * If we don't have lock info on the reln just go ahead and
-	 * release it.
-	 * ----------------
-	 */
 	if (!LockInfoIsValid(lockinfo))
 	{
 		elog(ERROR,
@@ -213,84 +211,50 @@ RelationUnsetLockForRead(Relation relation)
 			 RelationGetRelationName(relation));
 	}
 
-	MultiReleaseReln(lockinfo, READ_LOCK);
-}
+	MemSet(&tag, 0, sizeof(tag));
+	tag.relId = lockinfo->lockRelId.relId;
+	tag.dbId = lockinfo->lockRelId.dbId;
+	tag.objId.blkno = InvalidBlockNumber;
 
-/* ----------------
- *		RelationSetLockForWrite(relation)
- * ----------------
- */
-#ifdef	LOCKDEBUG
-#define LOCKDEBUG_60 \
-elog(DEBUG, "RelationSetLockForWrite(%s[%d,%d]) called", \
-	 RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId)
-#else
-#define LOCKDEBUG_60
-#endif	 /* LOCKDEBUG */
+	LockRelease(LockTableId, &tag, lockmode);
+	return;
+}
 
 /*
- * RelationSetLockForWrite --
- *		Sets relation level write lock.
+ *		LockPage
  */
 void
-RelationSetLockForWrite(Relation relation)
+LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
 {
 	LockInfo	lockinfo;
+	LOCKTAG		tag;
 
-	/* ----------------
-	 *	sanity checks
-	 * ----------------
-	 */
-	Assert(RelationIsValid(relation));
 	if (LockingDisabled())
 		return;
 
-	LOCKDEBUG_60;
-
-	/* ----------------
-	 * If we don't have lock info on the reln just go ahead and
-	 * lock it without trying to short circuit the lock manager.
-	 * ----------------
-	 */
 	if (!LockInfoIsValid(relation->lockInfo))
-	{
 		RelationInitLockInfo(relation);
-		lockinfo = (LockInfo) relation->lockInfo;
-		MultiLockReln(lockinfo, WRITE_LOCK);
-		return;
-	}
-	else
-		lockinfo = (LockInfo) relation->lockInfo;
 
-	MultiLockReln(lockinfo, WRITE_LOCK);
-}
+	lockinfo = (LockInfo) relation->lockInfo;
 
-/* ----------------
- *		RelationUnsetLockForWrite
- * ----------------
- */
-#ifdef	LOCKDEBUG
-#define LOCKDEBUG_70 \
-elog(DEBUG, "RelationUnsetLockForWrite(%s[%d,%d]) called", \
-	 RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId)
-#else
-#define LOCKDEBUG_70
-#endif	 /* LOCKDEBUG */
+	MemSet(&tag, 0, sizeof(tag));
+	tag.relId = lockinfo->lockRelId.relId;
+	tag.dbId = lockinfo->lockRelId.dbId;
+	tag.objId.blkno = blkno;
+
+	LockAcquire(LockTableId, &tag, lockmode);
+	return;
+}
 
 /*
- * RelationUnsetLockForWrite --
- *		Unsets relation level write lock.
+ *		UnlockPage
  */
 void
-RelationUnsetLockForWrite(Relation relation)
+UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
 {
 	LockInfo	lockinfo;
+	LOCKTAG		tag;
 
-	/* ----------------
-	 *	sanity checks
-	 * ----------------
-	 */
-	Assert(RelationIsValid(relation));
 	if (LockingDisabled())
 		return;
 
@@ -303,309 +267,71 @@ RelationUnsetLockForWrite(Relation relation)
 			 RelationGetRelationName(relation));
 	}
 
-	MultiReleaseReln(lockinfo, WRITE_LOCK);
-}
+	MemSet(&tag, 0, sizeof(tag));
+	tag.relId = lockinfo->lockRelId.relId;
+	tag.dbId = lockinfo->lockRelId.dbId;
+	tag.objId.blkno = blkno;
 
-/* ----------------
- *		RelationSetLockForReadPage
- * ----------------
- */
-#ifdef	LOCKDEBUG
-#define LOCKDEBUG_90 \
-elog(DEBUG, "RelationSetLockForReadPage(%s[%d,%d], @%d) called", \
-	 RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId, page)
-#else
-#define LOCKDEBUG_90
-#endif	 /* LOCKDEBUG */
-
-/* ----------------
- *		RelationSetLockForWritePage
- * ----------------
- */
-#ifdef	LOCKDEBUG
-#define LOCKDEBUG_100 \
-elog(DEBUG, "RelationSetLockForWritePage(%s[%d,%d], @%d) called", \
-	 RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId, page)
-#else
-#define LOCKDEBUG_100
-#endif	 /* LOCKDEBUG */
-
-/*
- * RelationSetLockForWritePage --
- *		Sets write lock on a page.
- */
-void
-RelationSetLockForWritePage(Relation relation,
-							ItemPointer itemPointer)
-{
-	/* ----------------
-	 *	sanity checks
-	 * ----------------
-	 */
-	Assert(RelationIsValid(relation));
-	if (LockingDisabled())
-		return;
-
-	/* ---------------
-	 * Make sure lockinfo is initialized
-	 * ---------------
-	 */
-	if (!LockInfoIsValid(relation->lockInfo))
-		RelationInitLockInfo(relation);
-
-	/* ----------------
-	 *	attempt to set lock
-	 * ----------------
-	 */
-	MultiLockPage((LockInfo) relation->lockInfo, itemPointer, WRITE_LOCK);
+	LockRelease(LockTableId, &tag, lockmode);
+	return;
 }
 
-/* ----------------
- *		RelationUnsetLockForReadPage
- * ----------------
- */
-#ifdef	LOCKDEBUG
-#define LOCKDEBUG_110 \
-elog(DEBUG, "RelationUnsetLockForReadPage(%s[%d,%d], @%d) called", \
-	 RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId, page)
-#else
-#define LOCKDEBUG_110
-#endif	 /* LOCKDEBUG */
-
-/* ----------------
- *		RelationUnsetLockForWritePage
- * ----------------
- */
-#ifdef	LOCKDEBUG
-#define LOCKDEBUG_120 \
-elog(DEBUG, "RelationUnsetLockForWritePage(%s[%d,%d], @%d) called", \
-	 RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId, page)
-#else
-#define LOCKDEBUG_120
-#endif	 /* LOCKDEBUG */
-
-/*
- * Set a single level write page lock.	Assumes that you already
- * have a write intent lock on the relation.
- */
 void
-RelationSetSingleWLockPage(Relation relation,
-						   ItemPointer itemPointer)
+XactLockTableInsert(TransactionId xid)
 {
+	LOCKTAG		tag;
 
-	/* ----------------
-	 *	sanity checks
-	 * ----------------
-	 */
-	Assert(RelationIsValid(relation));
 	if (LockingDisabled())
 		return;
 
-	if (!LockInfoIsValid(relation->lockInfo))
-		RelationInitLockInfo(relation);
+	MemSet(&tag, 0, sizeof(tag));
+	tag.relId = XactLockTableId;
+	tag.dbId = InvalidOid;
+	tag.objId.xid = xid;
 
-	SingleLockPage((LockInfo) relation->lockInfo, itemPointer, WRITE_LOCK, !UNLOCK);
+	LockAcquire(LockTableId, &tag, ExclusiveLock);
+	return;
 }
 
-/*
- * Unset a single level write page lock
- */
 void
-RelationUnsetSingleWLockPage(Relation relation,
-							 ItemPointer itemPointer)
+XactLockTableDelete(TransactionId xid)
 {
+	LOCKTAG		tag;
 
-	/* ----------------
-	 *	sanity checks
-	 * ----------------
-	 */
-	Assert(RelationIsValid(relation));
 	if (LockingDisabled())
 		return;
 
-	if (!LockInfoIsValid(relation->lockInfo))
-		elog(ERROR,
-			 "Releasing a lock on %s with invalid lock information",
-			 RelationGetRelationName(relation));
-
-	SingleLockPage((LockInfo) relation->lockInfo, itemPointer, WRITE_LOCK, UNLOCK);
-}
-
-/*
- * Set a single level read page lock.  Assumes you already have a read
- * intent lock set on the relation.
- */
-void
-RelationSetSingleRLockPage(Relation relation,
-						   ItemPointer itemPointer)
-{
-
-	/* ----------------
-	 *	sanity checks
-	 * ----------------
-	 */
-	Assert(RelationIsValid(relation));
-	if (LockingDisabled())
-		return;
-
-	if (!LockInfoIsValid(relation->lockInfo))
-		RelationInitLockInfo(relation);
-
-	SingleLockPage((LockInfo) relation->lockInfo, itemPointer, READ_LOCK, !UNLOCK);
-}
-
-/*
- * Unset a single level read page lock.
- */
-void
-RelationUnsetSingleRLockPage(Relation relation,
-							 ItemPointer itemPointer)
-{
-
-	/* ----------------
-	 *	sanity checks
-	 * ----------------
-	 */
-	Assert(RelationIsValid(relation));
-	if (LockingDisabled())
-		return;
-
-	if (!LockInfoIsValid(relation->lockInfo))
-		elog(ERROR,
-			 "Releasing a lock on %s with invalid lock information",
-			 RelationGetRelationName(relation));
-
-	SingleLockPage((LockInfo) relation->lockInfo, itemPointer, READ_LOCK, UNLOCK);
-}
-
-/*
- * Set a read intent lock on a relation.
- *
- * Usually these are set in a multi-level table when you acquiring a
- * page level lock.  i.e. To acquire a lock on a page you first acquire
- * an intent lock on the entire relation.  Acquiring an intent lock along
- * allows one to use the single level locking routines later.  Good for
- * index scans that do a lot of page level locking.
- */
-void
-RelationSetRIntentLock(Relation relation)
-{
-	/* -----------------
-	 * Sanity check
-	 * -----------------
-	 */
-	Assert(RelationIsValid(relation));
-	if (LockingDisabled())
-		return;
-
-	if (!LockInfoIsValid(relation->lockInfo))
-		RelationInitLockInfo(relation);
-
-	SingleLockReln((LockInfo) relation->lockInfo, READ_LOCK + INTENT, !UNLOCK);
-}
-
-/*
- * Unset a read intent lock on a relation
- */
-void
-RelationUnsetRIntentLock(Relation relation)
-{
-	/* -----------------
-	 * Sanity check
-	 * -----------------
-	 */
-	Assert(RelationIsValid(relation));
-	if (LockingDisabled())
-		return;
-
-	if (!LockInfoIsValid(relation->lockInfo))
-		RelationInitLockInfo(relation);
+	MemSet(&tag, 0, sizeof(tag));
+	tag.relId = XactLockTableId;
+	tag.dbId = InvalidOid;
+	tag.objId.xid = xid;
 
-	SingleLockReln((LockInfo) relation->lockInfo, READ_LOCK + INTENT, UNLOCK);
+	LockRelease(LockTableId, &tag, ExclusiveLock);
+	return;
 }
 
-/*
- * Set a write intent lock on a relation. For a more complete explanation
- * see RelationSetRIntentLock()
- */
 void
-RelationSetWIntentLock(Relation relation)
+XactLockTableWait(TransactionId xid)
 {
-	/* -----------------
-	 * Sanity check
-	 * -----------------
-	 */
-	Assert(RelationIsValid(relation));
-	if (LockingDisabled())
-		return;
-
-	if (!LockInfoIsValid(relation->lockInfo))
-		RelationInitLockInfo(relation);
+	LOCKTAG		tag;
 
-	SingleLockReln((LockInfo) relation->lockInfo, WRITE_LOCK + INTENT, !UNLOCK);
-}
-
-/*
- * Unset a write intent lock.
- */
-void
-RelationUnsetWIntentLock(Relation relation)
-{
-	/* -----------------
-	 * Sanity check
-	 * -----------------
-	 */
-	Assert(RelationIsValid(relation));
 	if (LockingDisabled())
 		return;
 
-	if (!LockInfoIsValid(relation->lockInfo))
-		RelationInitLockInfo(relation);
+	MemSet(&tag, 0, sizeof(tag));
+	tag.relId = XactLockTableId;
+	tag.dbId = InvalidOid;
+	tag.objId.xid = xid;
 
-	SingleLockReln((LockInfo) relation->lockInfo, WRITE_LOCK + INTENT, UNLOCK);
-}
+	LockAcquire(LockTableId, &tag, ShareLock);
 
-/*
- * Extend locks are used primarily in tertiary storage devices such as
- * a WORM disk jukebox.  Sometimes need exclusive access to extend a
- * file by a block.
- */
-#ifdef NOT_USED
-void
-RelationSetLockForExtend(Relation relation)
-{
-	/* -----------------
-	 * Sanity check
-	 * -----------------
+	/*
+	 * Transaction was committed/aborted/crashed - 
+	 * we have to update pg_log if transaction is still
+	 * marked as running.
 	 */
-	Assert(RelationIsValid(relation));
-	if (LockingDisabled())
-		return;
-
-	if (!LockInfoIsValid(relation->lockInfo))
-		RelationInitLockInfo(relation);
+	if (!TransactionIdDidCommit(xid) && !TransactionIdDidAbort(xid))
+		TransactionIdAbort(xid);
 
-	MultiLockReln((LockInfo) relation->lockInfo, EXTEND_LOCK);
+	return;
 }
-
-#endif
-
-#ifdef NOT_USED
-void
-RelationUnsetLockForExtend(Relation relation)
-{
-	/* -----------------
-	 * Sanity check
-	 * -----------------
-	 */
-	Assert(RelationIsValid(relation));
-	if (LockingDisabled())
-		return;
-
-	if (!LockInfoIsValid(relation->lockInfo))
-		RelationInitLockInfo(relation);
-
-	MultiReleaseReln((LockInfo) relation->lockInfo, EXTEND_LOCK);
-}
-
-#endif
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index adc4d1a42ea..7fdd8fec843 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.38 1998/10/08 18:29:57 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.39 1998/12/15 12:46:30 vadim Exp $
  *
  * NOTES
  *	  Outside modules can create a lock table and acquire/release
@@ -84,7 +84,7 @@ static int WaitOnLock(LOCKMETHOD lockmethod, LOCK *lock, LOCKMODE lockmode,
 
 #define LOCK_PRINT_AUX(where,lock,type) \
 	TPRINTF(TRACE_ALL, \
-		 "%s: lock(%x) tbl(%d) rel(%d) db(%d) tid(%d,%d) mask(%x) " \
+		 "%s: lock(%x) tbl(%d) rel(%d) db(%d) obj(%u) mask(%x) " \
 		 "hold(%d,%d,%d,%d,%d)=%d " \
 		 "act(%d,%d,%d,%d,%d)=%d wait(%d) type(%s)", \
 		 where, \
@@ -92,9 +92,7 @@ static int WaitOnLock(LOCKMETHOD lockmethod, LOCK *lock, LOCKMODE lockmode,
 		 lock->tag.lockmethod, \
 		 lock->tag.relId, \
 		 lock->tag.dbId, \
-		 ((lock->tag.tupleId.ip_blkid.bi_hi<<16)+ \
-		  lock->tag.tupleId.ip_blkid.bi_lo), \
-		 lock->tag.tupleId.ip_posid, \
+		 lock->tag.objId.blkno, \
 		 lock->mask, \
 		 lock->holders[1], \
 		 lock->holders[2], \
@@ -498,10 +496,8 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag, LOCKMODE lockmode)
 	if (is_user_lock)
 	{
 #ifdef USER_LOCKS_DEBUG
-		TPRINTF(TRACE_USERLOCKS, "LockAcquire: user lock [%u,%u] %s",
-				locktag->tupleId.ip_posid,
-				((locktag->tupleId.ip_blkid.bi_hi << 16) +
-				 locktag->tupleId.ip_blkid.bi_lo),
+		TPRINTF(TRACE_USERLOCKS, "LockAcquire: user lock [%u] %s",
+				locktag->objId.blkno,
 				lock_types[lockmode]);
 #endif
 	}
@@ -550,8 +546,7 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag, LOCKMODE lockmode)
 		MemSet((char *) lock->holders, 0, sizeof(int) * MAX_LOCKMODES);
 		MemSet((char *) lock->activeHolders, 0, sizeof(int) * MAX_LOCKMODES);
 		ProcQueueInit(&(lock->waitProcs));
-		Assert(BlockIdEquals(&(lock->tag.tupleId.ip_blkid),
-							 &(locktag->tupleId.ip_blkid)));
+		Assert(lock->tag.objId.blkno == locktag->objId.blkno);
 		LOCK_PRINT("LockAcquire: new", lock, lockmode);
 	}
 	else
@@ -993,10 +988,8 @@ LockRelease(LOCKMETHOD lockmethod, LOCKTAG *locktag, LOCKMODE lockmode)
 	is_user_lock = (lockmethod == USER_LOCKMETHOD);
 	if (is_user_lock)
 	{
-		TPRINTF(TRACE_USERLOCKS, "LockRelease: user lock tag [%u,%u] %d",
-				locktag->tupleId.ip_posid,
-				((locktag->tupleId.ip_blkid.bi_hi << 16) +
-				 locktag->tupleId.ip_blkid.bi_lo),
+		TPRINTF(TRACE_USERLOCKS, "LockRelease: user lock tag [%u] %d",
+				locktag->objId.blkno,
 				lockmode);
 	}
 #endif
@@ -1336,19 +1329,15 @@ LockReleaseAll(LOCKMETHOD lockmethod, SHM_QUEUE *lockQueue)
 			{
 				/* Should never happen */
 				elog(NOTICE,
-					 "LockReleaseAll: INVALID PID: [%u,%u] [%d,%d,%d]",
-					 lock->tag.tupleId.ip_posid,
-					 ((lock->tag.tupleId.ip_blkid.bi_hi << 16) +
-					  lock->tag.tupleId.ip_blkid.bi_lo),
+					 "LockReleaseAll: INVALID PID: [%u] [%d,%d,%d]",
+					 lock->tag.objId.blkno,
 				  xidLook->tag.lock, xidLook->tag.pid, xidLook->tag.xid);
 				nleft++;
 				goto next_item;
 			}
 			TPRINTF(TRACE_USERLOCKS,
-				"LockReleaseAll: releasing user lock [%u,%u] [%d,%d,%d]",
-					lock->tag.tupleId.ip_posid,
-					((lock->tag.tupleId.ip_blkid.bi_hi << 16) +
-					 lock->tag.tupleId.ip_blkid.bi_lo),
+				"LockReleaseAll: releasing user lock [%u] [%d,%d,%d]",
+					lock->tag.objId.blkno,
 				  xidLook->tag.lock, xidLook->tag.pid, xidLook->tag.xid);
 		}
 		else
@@ -1361,10 +1350,8 @@ LockReleaseAll(LOCKMETHOD lockmethod, SHM_QUEUE *lockQueue)
 			if (xidLook->tag.pid != 0)
 			{
 				TPRINTF(TRACE_LOCKS,
-				  "LockReleaseAll: skiping user lock [%u,%u] [%d,%d,%d]",
-						lock->tag.tupleId.ip_posid,
-						((lock->tag.tupleId.ip_blkid.bi_hi << 16) +
-						 lock->tag.tupleId.ip_blkid.bi_lo),
+				  "LockReleaseAll: skiping user lock [%u] [%d,%d,%d]",
+						lock->tag.objId.blkno,
 				  xidLook->tag.lock, xidLook->tag.pid, xidLook->tag.xid);
 				nleft++;
 				goto next_item;
@@ -1649,7 +1636,7 @@ DeadLockCheck(SHM_QUEUE *lockQueue, LOCK *findlock, bool skip_check)
 					 */
 
 					Assert(skip_check);
-					Assert(MyProc->prio == 2);
+					Assert(MyProc->prio >= 2);
 
 					lockMethodTable = LockMethodTable[1];
 					xidTable = lockMethodTable->xidHash;
@@ -1747,10 +1734,8 @@ LockOwners(LOCKMETHOD lockmethod, LOCKTAG *locktag)
 	is_user_lock = (lockmethod == USER_LOCKMETHOD);
 	if (is_user_lock)
 	{
-		TPRINTF(TRACE_USERLOCKS, "LockOwners: user lock tag [%u,%u]",
-				locktag->tupleId.ip_posid,
-				((locktag->tupleId.ip_blkid.bi_hi << 16) +
-				 locktag->tupleId.ip_blkid.bi_lo));
+		TPRINTF(TRACE_USERLOCKS, "LockOwners: user lock tag [%u]",
+				locktag->objId.blkno;,
 	}
 #endif
 
diff --git a/src/backend/utils/adt/sets.c b/src/backend/utils/adt/sets.c
index a9c669bc3aa..6553e73214c 100644
--- a/src/backend/utils/adt/sets.c
+++ b/src/backend/utils/adt/sets.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.19 1998/11/27 19:52:23 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.20 1998/12/15 12:46:34 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -109,7 +109,7 @@ SetDefine(char *querystr, char *typename)
 
 		/* change the pg_proc tuple */
 		procrel = heap_openr(ProcedureRelationName);
-		RelationSetLockForWrite(procrel);
+		LockRelation(procrel, AccessExclusiveLock);
 
 		tup = SearchSysCacheTuple(PROOID,
 								  ObjectIdGetDatum(setoid),
@@ -123,7 +123,7 @@ SetDefine(char *querystr, char *typename)
 									  repl);
 
 			setheapoverride(true);
-			heap_replace(procrel, &tup->t_self, newtup);
+			heap_replace(procrel, &tup->t_self, newtup, NULL);
 			setheapoverride(false);
 
 			setoid = newtup->t_data->t_oid;
@@ -139,7 +139,7 @@ SetDefine(char *querystr, char *typename)
 			CatalogIndexInsert(idescs, Num_pg_proc_indices, procrel, newtup);
 			CatalogCloseIndices(Num_pg_proc_indices, idescs);
 		}
-		RelationUnsetLockForWrite(procrel);
+		UnlockRelation(procrel, AccessExclusiveLock);
 		heap_close(procrel);
 	}
 	return setoid;
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 492eba6f659..99ee3d2fc54 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.51 1998/11/27 19:52:28 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.52 1998/12/15 12:46:37 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -363,8 +363,6 @@ scan_pg_rel_seq(RelationBuildDescInfo buildinfo)
 	 * ----------------
 	 */
 	pg_class_desc = heap_openr(RelationRelationName);
-	if (!IsInitProcessingMode())
-		RelationSetLockForRead(pg_class_desc);
 	pg_class_scan = heap_beginscan(pg_class_desc, 0, SnapshotNow, 1, &key);
 	pg_class_tuple = heap_getnext(pg_class_scan, 0);
 
@@ -388,8 +386,6 @@ scan_pg_rel_seq(RelationBuildDescInfo buildinfo)
 
 	/* all done */
 	heap_endscan(pg_class_scan);
-	if (!IsInitProcessingMode())
-		RelationUnsetLockForRead(pg_class_desc);
 	heap_close(pg_class_desc);
 
 	return return_tuple;
@@ -403,7 +399,7 @@ scan_pg_rel_ind(RelationBuildDescInfo buildinfo)
 
 	pg_class_desc = heap_openr(RelationRelationName);
 	if (!IsInitProcessingMode())
-		RelationSetLockForRead(pg_class_desc);
+		LockRelation(pg_class_desc, AccessShareLock);
 
 	switch (buildinfo.infotype)
 	{
@@ -428,7 +424,7 @@ scan_pg_rel_ind(RelationBuildDescInfo buildinfo)
 
 	/* all done */
 	if (!IsInitProcessingMode())
-		RelationUnsetLockForRead(pg_class_desc);
+		UnlockRelation(pg_class_desc, AccessShareLock);
 	heap_close(pg_class_desc);
 
 	return return_tuple;
@@ -1126,7 +1122,6 @@ RelationIdCacheGetRelation(Oid relationId)
 		}
 
 		RelationIncrementReferenceCount(rd);
-		RelationSetLockForDescriptorOpen(rd);
 
 	}
 
@@ -1159,7 +1154,6 @@ RelationNameCacheGetRelation(char *relationName)
 		}
 
 		RelationIncrementReferenceCount(rd);
-		RelationSetLockForDescriptorOpen(rd);
 
 	}
 
diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c
index c88646151a7..f53fdd72720 100644
--- a/src/backend/utils/time/tqual.c
+++ b/src/backend/utils/time/tqual.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/time/tqual.c,v 1.20 1998/11/27 19:52:36 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/time/tqual.c,v 1.21 1998/12/15 12:46:40 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -26,6 +26,9 @@
 
 extern bool PostgresIsInitialized;
 
+SnapshotData	SnapshotDirtyData;
+Snapshot		SnapshotDirty = &SnapshotDirtyData;
+
 /*
  * XXX Transaction system override hacks start here
  */
@@ -88,8 +91,9 @@ HeapTupleSatisfiesItself(HeapTupleHeader tuple)
 		{
 			if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid */
 				return true;
-			else
-				return false;
+			if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
+				return true;
+			return false;
 		}
 
 		if (!TransactionIdDidCommit(tuple->t_xmin))
@@ -107,10 +111,18 @@ HeapTupleSatisfiesItself(HeapTupleHeader tuple)
 		return true;
 
 	if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
-		return false;
+	{
+		if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
+			return true;
+		return false;							/* updated by other */
+	}
 
 	if (TransactionIdIsCurrentTransactionId(tuple->t_xmax))
+	{
+		if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
+			return true;
 		return false;
+	}
 
 	if (!TransactionIdDidCommit(tuple->t_xmax))
 	{
@@ -122,6 +134,9 @@ HeapTupleSatisfiesItself(HeapTupleHeader tuple)
 	/* by here, deleting transaction has committed */
 	tuple->t_infomask |= HEAP_XMAX_COMMITTED;
 
+	if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
+		return true;
+
 	return false;
 }
 
@@ -152,13 +167,6 @@ HeapTupleSatisfiesItself(HeapTupleHeader tuple)
  *			(Xmax is not committed &&			the row was deleted by another transaction
  *			 Xmax != my-transaction))))			that has not been committed
  *
- * XXX
- *		CommandId stuff didn't work properly if one used SQL-functions in
- *		UPDATE/INSERT(fromSELECT)/DELETE scans: SQL-funcs call
- *		CommandCounterIncrement and made tuples changed/inserted by
- *		current command visible to command itself (so we had multiple
- *		update of updated tuples, etc).			- vadim 08/29/97
- *
  *		mao says 17 march 1993:  the tests in this routine are correct;
  *		if you think they're not, you're wrong, and you should think
  *		about it again.  i know, it happened to me.  we don't need to
@@ -203,6 +211,9 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple)
 
 			Assert(TransactionIdIsCurrentTransactionId(tuple->t_xmax));
 
+			if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
+				return true;
+
 			if (CommandIdGEScanCommandId(tuple->t_cmax))
 				return true;	/* deleted after scan started */
 			else
@@ -229,10 +240,16 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple)
 		return true;
 
 	if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
+	{
+		if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
+			return true;
 		return false;
+	}
 
 	if (TransactionIdIsCurrentTransactionId(tuple->t_xmax))
 	{
+		if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
+			return true;
 		if (CommandIdGEScanCommandId(tuple->t_cmax))
 			return true;		/* deleted after scan started */
 		else
@@ -249,5 +266,173 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple)
 	/* xmax transaction committed */
 	tuple->t_infomask |= HEAP_XMAX_COMMITTED;
 
+	if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
+		return true;
+
 	return false;
 }
+
+int
+HeapTupleSatisfiesUpdate(HeapTuple tuple)
+{
+	HeapTupleHeader	th = tuple->t_data;
+
+	if (AMI_OVERRIDE)
+		return HeapTupleMayBeUpdated;
+
+	if (!(th->t_infomask & HEAP_XMIN_COMMITTED))
+	{
+		if (th->t_infomask & HEAP_XMIN_INVALID)	/* xid invalid or aborted */
+			return HeapTupleInvisible;
+
+		if (TransactionIdIsCurrentTransactionId(th->t_xmin))
+		{
+			if (CommandIdGEScanCommandId(th->t_cmin) && !heapisoverride())
+				return HeapTupleInvisible;	/* inserted after scan started */
+
+			if (th->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid */
+				return HeapTupleMayBeUpdated;
+
+			Assert(TransactionIdIsCurrentTransactionId(th->t_xmax));
+
+			if (th->t_infomask & HEAP_MARKED_FOR_UPDATE)
+				return HeapTupleMayBeUpdated;
+
+			if (CommandIdGEScanCommandId(th->t_cmax))
+				return HeapTupleSelfUpdated;/* updated after scan started */
+			else
+				return HeapTupleInvisible;	/* updated before scan started */
+		}
+
+		/*
+		 * This call is VERY expensive - requires a log table lookup.
+		 * Actually, this should be done by query before...
+		 */
+
+		if (!TransactionIdDidCommit(th->t_xmin))
+		{
+			if (TransactionIdDidAbort(th->t_xmin))
+				th->t_infomask |= HEAP_XMIN_INVALID; /* aborted */
+			return HeapTupleInvisible;
+		}
+
+		th->t_infomask |= HEAP_XMIN_COMMITTED;
+	}
+
+	/* by here, the inserting transaction has committed */
+
+	if (th->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid or aborted */
+		return HeapTupleMayBeUpdated;
+
+	if (th->t_infomask & HEAP_XMAX_COMMITTED)
+	{
+		if (th->t_infomask & HEAP_MARKED_FOR_UPDATE)
+			return HeapTupleMayBeUpdated;
+		return HeapTupleUpdated;			/* updated by other */
+	}
+
+	if (TransactionIdIsCurrentTransactionId(th->t_xmax))
+	{
+		if (th->t_infomask & HEAP_MARKED_FOR_UPDATE)
+			return HeapTupleMayBeUpdated;
+		if (CommandIdGEScanCommandId(th->t_cmax))
+			return HeapTupleSelfUpdated;/* updated after scan started */
+		else
+			return HeapTupleInvisible;	/* updated before scan started */
+	}
+
+	if (!TransactionIdDidCommit(th->t_xmax))
+	{
+		if (TransactionIdDidAbort(th->t_xmax))
+		{
+			th->t_infomask |= HEAP_XMAX_INVALID;		/* aborted */
+			return HeapTupleMayBeUpdated;
+		}
+		/* running xact */
+		return HeapTupleBeingUpdated;	/* in updation by other */
+	}
+
+	/* xmax transaction committed */
+	th->t_infomask |= HEAP_XMAX_COMMITTED;
+
+	if (th->t_infomask & HEAP_MARKED_FOR_UPDATE)
+		return HeapTupleMayBeUpdated;
+
+	return HeapTupleUpdated;			/* updated by other */
+}
+
+bool
+HeapTupleSatisfiesDirty(HeapTupleHeader tuple)
+{
+	SnapshotDirty->xmin = SnapshotDirty->xmax = InvalidTransactionId;
+
+	if (AMI_OVERRIDE)
+		return true;
+
+	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
+	{
+		if (tuple->t_infomask & HEAP_XMIN_INVALID)	/* xid invalid or aborted */
+			return false;
+
+		if (TransactionIdIsCurrentTransactionId(tuple->t_xmin))
+		{
+			if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid */
+				return true;
+
+			Assert(TransactionIdIsCurrentTransactionId(tuple->t_xmax));
+
+			if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
+				return true;
+
+			return false;
+		}
+
+		if (!TransactionIdDidCommit(tuple->t_xmin))
+		{
+			if (TransactionIdDidAbort(tuple->t_xmin))
+			{
+				tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */
+				return false;
+			}
+			SnapshotDirty->xmin = tuple->t_xmin;
+			return true;						/* in insertion by other */
+		}
+
+		tuple->t_infomask |= HEAP_XMIN_COMMITTED;
+	}
+
+	/* by here, the inserting transaction has committed */
+
+	if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid or aborted */
+		return true;
+
+	if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
+	{
+		if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
+			return true;
+		return false;							/* updated by other */
+	}
+
+	if (TransactionIdIsCurrentTransactionId(tuple->t_xmax))
+		return false;
+
+	if (!TransactionIdDidCommit(tuple->t_xmax))
+	{
+		if (TransactionIdDidAbort(tuple->t_xmax))
+		{
+			tuple->t_infomask |= HEAP_XMAX_INVALID;		/* aborted */
+			return true;
+		}
+		/* running xact */
+		SnapshotDirty->xmax = tuple->t_xmax;
+		return true;							/* in updation by other */
+	}
+
+	/* xmax transaction committed */
+	tuple->t_infomask |= HEAP_XMAX_COMMITTED;
+
+	if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
+		return true;
+
+	return false;								/* updated by other */
+}
diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h
index 0c756e0beba..e883c7f0a50 100644
--- a/src/include/access/heapam.h
+++ b/src/include/access/heapam.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: heapam.h,v 1.39 1998/11/27 19:33:31 vadim Exp $
+ * $Id: heapam.h,v 1.40 1998/12/15 12:46:44 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -42,6 +42,7 @@ typedef struct HeapAccessStatisticsData
 	int			global_insert;
 	int			global_delete;
 	int			global_replace;
+	int			global_mark4update;
 	int			global_markpos;
 	int			global_restrpos;
 	int			global_BufferGetRelation;
@@ -64,6 +65,7 @@ typedef struct HeapAccessStatisticsData
 	int			local_insert;
 	int			local_delete;
 	int			local_replace;
+	int			local_mark4update;
 	int			local_markpos;
 	int			local_restrpos;
 	int			local_BufferGetRelation;
@@ -253,9 +255,10 @@ extern void heap_endscan(HeapScanDesc scan);
 extern HeapTuple heap_getnext(HeapScanDesc scandesc, int backw);
 extern void heap_fetch(Relation relation, Snapshot snapshot, HeapTuple tup, Buffer *userbuf);
 extern Oid	heap_insert(Relation relation, HeapTuple tup);
-extern int	heap_delete(Relation relation, ItemPointer tid);
-extern int heap_replace(Relation relation, ItemPointer otid,
-			 HeapTuple tup);
+extern int	heap_delete(Relation relation, ItemPointer tid, ItemPointer ctid);
+extern int	heap_replace(Relation relation, ItemPointer otid, HeapTuple tup,
+							ItemPointer ctid);
+extern int	heap_mark4update(Relation relation, HeapTuple tup, Buffer *userbuf);
 extern void heap_markpos(HeapScanDesc scan);
 extern void heap_restrpos(HeapScanDesc scan);
 
@@ -281,9 +284,4 @@ HeapTuple	heap_addheader(uint32 natts, int structlen, char *structure);
 extern void PrintHeapAccessStatistics(HeapAccessStatistics stats);
 extern void initam(void);
 
-/* hio.c */
-extern void RelationPutHeapTuple(Relation relation, BlockNumber blockIndex,
-					 HeapTuple tuple);
-extern void RelationPutHeapTupleAtEnd(Relation relation, HeapTuple tuple);
-
 #endif	 /* HEAPAM_H */
diff --git a/src/include/access/hio.h b/src/include/access/hio.h
index caa5380083d..eb8a955b4d0 100644
--- a/src/include/access/hio.h
+++ b/src/include/access/hio.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: hio.h,v 1.8 1998/09/01 04:34:13 momjian Exp $
+ * $Id: hio.h,v 1.9 1998/12/15 12:46:45 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,8 +17,8 @@
 #include <utils/rel.h>
 
 
-extern void RelationPutHeapTuple(Relation relation, BlockNumber blockIndex,
-					 HeapTuple tuple);
+extern void RelationPutHeapTuple(Relation relation, Buffer buffer, 
+									HeapTuple tuple);
 extern void RelationPutHeapTupleAtEnd(Relation relation, HeapTuple tuple);
 
 #endif	 /* HIO_H */
diff --git a/src/include/access/htup.h b/src/include/access/htup.h
index 56197048ba0..06c62a9a4d9 100644
--- a/src/include/access/htup.h
+++ b/src/include/access/htup.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: htup.h,v 1.11 1998/11/27 19:33:31 vadim Exp $
+ * $Id: htup.h,v 1.12 1998/12/15 12:46:46 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -116,6 +116,7 @@ typedef HeapTupleData *HeapTuple;
 #define HEAP_XMIN_INVALID		0x0200	/* t_xmin invalid/aborted */
 #define HEAP_XMAX_COMMITTED		0x0400	/* t_xmax committed */
 #define HEAP_XMAX_INVALID		0x0800	/* t_xmax invalid/aborted */
+#define HEAP_MARKED_FOR_UPDATE	0x1000	/* marked for UPDATE */
 
 #define HEAP_XACT_MASK			0x0F00	/* */
 
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index e4c1e0a88ce..6b0aae443f0 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: xact.h,v 1.17 1998/10/08 18:30:23 momjian Exp $
+ * $Id: xact.h,v 1.18 1998/12/15 12:46:47 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -38,6 +38,8 @@ typedef struct TransactionStateData
 #define XACT_REPEATABLE_READ	2		/* not implemented */
 #define XACT_SERIALIZED			3
 
+extern int	XactIsoLevel;
+
 /* ----------------
  *		transaction states
  * ----------------
diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h
index 3106ffa7cc1..bc3b9da1def 100644
--- a/src/include/catalog/pg_am.h
+++ b/src/include/catalog/pg_am.h
@@ -7,7 +7,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_am.h,v 1.9 1998/09/01 04:34:47 momjian Exp $
+ * $Id: pg_am.h,v 1.10 1998/12/15 12:46:49 vadim Exp $
  *
  * NOTES
  *		the genbki.sh script reads this file and generates .bki
@@ -106,6 +106,7 @@ DESCR("");
 #define BTREE_AM_OID 403
 DATA(insert OID = 405 (  hash PGUID "o"  1 1 hashgettuple hashinsert hashdelete - - - - hashbeginscan hashrescan hashendscan hashmarkpos hashrestrpos - - hashbuild - - ));
 DESCR("");
+#define HASH_AM_OID 405
 DATA(insert OID = 783 (  gist PGUID "o" 100 7 gistgettuple gistinsert gistdelete - - - - gistbeginscan gistrescan gistendscan gistmarkpos gistrestrpos - - gistbuild - - ));
 DESCR("");
 
diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h
index c96e05e3939..c657375241a 100644
--- a/src/include/catalog/pg_class.h
+++ b/src/include/catalog/pg_class.h
@@ -7,7 +7,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_class.h,v 1.25 1998/09/10 15:32:31 vadim Exp $
+ * $Id: pg_class.h,v 1.26 1998/12/15 12:46:50 vadim Exp $
  *
  * NOTES
  *	  ``pg_relation'' is being replaced by ``pg_class''.  currently
@@ -144,6 +144,8 @@ DATA(insert OID = 1264 (  pg_variable 90	  PGUID 0 0 0 f t s 2  0 0 0 0 0 f f _n
 DESCR("");
 DATA(insert OID = 1269 (  pg_log  99		  PGUID 0 0 0 f t s 1  0 0 0 0 0 f f _null_ ));
 DESCR("");
+DATA(insert OID = 376  (  pg_xactlock  0 	  PGUID 0 0 0 f t s 1  0 0 0 0 0 f f _null_ ));
+DESCR("");
 DATA(insert OID = 1215 (  pg_attrdef 109	  PGUID 0 0 0 t t r 4  0 0 0 0 0 f f _null_ ));
 DESCR("");
 DATA(insert OID = 1216 (  pg_relcheck 110	  PGUID 0 0 0 t t r 4  0 0 0 0 0 f f _null_ ));
@@ -164,6 +166,9 @@ DESCR("");
 #define RelOid_pg_relcheck		1216
 #define RelOid_pg_trigger		1219
 
+/* Xact lock pseudo-table */
+#define XactLockTableId			376
+
 #define		  RELKIND_INDEX			  'i'		/* secondary index */
 #define		  RELKIND_LOBJECT		  'l'		/* large objects */
 #define		  RELKIND_RELATION		  'r'		/* cataloged heap */
diff --git a/src/include/commands/trigger.h b/src/include/commands/trigger.h
index 3cc0fdcc066..b52c81dc726 100644
--- a/src/include/commands/trigger.h
+++ b/src/include/commands/trigger.h
@@ -12,6 +12,7 @@
 #include "access/tupdesc.h"
 #include "access/htup.h"
 #include "nodes/parsenodes.h"
+#include "nodes/execnodes.h"
 #include "utils/rel.h"
 
 typedef uint32 TriggerEvent;
@@ -65,9 +66,9 @@ extern void RelationRemoveTriggers(Relation rel);
 
 extern HeapTuple ExecBRInsertTriggers(Relation rel, HeapTuple tuple);
 extern void ExecARInsertTriggers(Relation rel, HeapTuple tuple);
-extern bool ExecBRDeleteTriggers(Relation rel, ItemPointer tupleid);
-extern void ExecARDeleteTriggers(Relation rel, ItemPointer tupleid);
-extern HeapTuple ExecBRUpdateTriggers(Relation rel, ItemPointer tupleid, HeapTuple tuple);
-extern void ExecARUpdateTriggers(Relation rel, ItemPointer tupleid, HeapTuple tuple);
+extern bool ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid);
+extern void ExecARDeleteTriggers(EState *estate, ItemPointer tupleid);
+extern HeapTuple ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple tuple);
+extern void ExecARUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple tuple);
 
 #endif	 /* TRIGGER_H */
diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h
index 61f567b6d3b..383204c3f0f 100644
--- a/src/include/storage/buf_internals.h
+++ b/src/include/storage/buf_internals.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: buf_internals.h,v 1.26 1998/09/01 04:38:10 momjian Exp $
+ * $Id: buf_internals.h,v 1.27 1998/12/15 12:46:55 vadim Exp $
  *
  * NOTE
  *		If BUFFERPAGE0 is defined, then 0 will be used as a
@@ -83,32 +83,6 @@ struct buftag
  *		Dbname, relname, dbid, and relid are enough to determine where
  *		to put the buffer, for all storage managers.
  */
-
-#define PADDED_SBUFDESC_SIZE	128
-
-/* DO NOT CHANGE THIS NEXT STRUCTURE:
-   It is used only to get padding information for the real sbufdesc structure
-   It should match the sbufdesc structure exactly except for a missing sb_pad
-*/
-struct sbufdesc_unpadded
-{
-	Buffer		freeNext;
-	Buffer		freePrev;
-	SHMEM_OFFSET data;
-	BufferTag	tag;
-	int			buf_id;
-	BufFlags	flags;
-	unsigned	refcount;
-#ifdef HAS_TEST_AND_SET
-	slock_t		io_in_progress_lock;
-#endif	 /* HAS_TEST_AND_SET */
-	char		sb_dbname[NAMEDATALEN];
-
-	/* NOTE NO PADDING OF THE MEMBER HERE */
-	char		sb_relname[NAMEDATALEN];
-};
-
-/* THE REAL STRUCTURE - the structure above must match it, minus sb_pad */
 struct sbufdesc
 {
 	Buffer		freeNext;		/* link for freelist chain */
@@ -125,31 +99,25 @@ struct sbufdesc
 #ifdef HAS_TEST_AND_SET
 	/* can afford a dedicated lock if test-and-set locks are available */
 	slock_t		io_in_progress_lock;
+	slock_t		cntx_lock;		/* to lock access to page context */
 #endif	 /* HAS_TEST_AND_SET */
+	unsigned	r_locks;		/* # of shared locks */
+	bool		ri_lock;		/* read-intent lock */
+	bool		w_lock;			/* context exclusively locked */
 
 	char		sb_dbname[NAMEDATALEN]; /* name of db in which buf belongs */
-
-	/*
-	 * I padded this structure to a power of 2 (PADDED_SBUFDESC_SIZE)
-	 * because BufferDescriptorGetBuffer is called a billion times and it
-	 * does an C pointer subtraction (i.e., "x - y" -> array index of x
-	 * relative to y, which is calculated using division by struct size).
-	 * Integer ".div" hits you for 35 cycles, as opposed to a 1-cycle
-	 * "sra" ... this hack cut 10% off of the time to create the Wisconsin
-	 * database! It eats up more shared memory, of course, but we're
-	 * (allegedly) going to make some of these types bigger soon anyway...
-	 * -pma 1/2/93
-	 */
-
-	/*
-	 * please, don't take the sizeof() this member and use it for
-	 * something important
-	 */
-
-	char		sb_relname[NAMEDATALEN +		/* name of reln */
-				PADDED_SBUFDESC_SIZE - sizeof(struct sbufdesc_unpadded)];
+	char		sb_relname[NAMEDATALEN];/* name of reln */
 };
 
+/*
+ * Buffer lock infos in BufferLocks below.
+ * We have to free these locks in elog(ERROR)...
+ */
+#define	BL_IO_IN_PROGRESS	(1 << 0)	/* unimplemented */
+#define	BL_R_LOCK			(1 << 1)
+#define	BL_RI_LOCK			(1 << 2)
+#define	BL_W_LOCK			(1 << 3)
+
 /*
  *	mao tracing buffer allocation
  */
@@ -201,6 +169,7 @@ extern BufferDesc *BufferDescriptors;
 extern BufferBlock BufferBlocks;
 extern long *PrivateRefCount;
 extern long *LastRefCount;
+extern bits8 *BufferLocks;
 extern long *CommitInfoNeedsSave;
 extern SPINLOCK BufMgrLock;
 
diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h
index 1948e813ee3..22f66c2295b 100644
--- a/src/include/storage/bufmgr.h
+++ b/src/include/storage/bufmgr.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: bufmgr.h,v 1.23 1998/10/08 18:30:43 momjian Exp $
+ * $Id: bufmgr.h,v 1.24 1998/12/15 12:46:56 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -73,6 +73,14 @@ extern int	ShowPinTrace;
 #define BUFFER_FLUSH_WRITE		0		/* immediate write */
 #define BUFFER_LATE_WRITE		1		/* delayed write: mark as DIRTY */
 
+/*
+ * Buffer context lock modes
+ */
+#define	BUFFER_LOCK_UNLOCK		0
+#define	BUFFER_LOCK_SHARE		1
+#define	BUFFER_LOCK_EXCLUSIVE	2
+
+
 /*
  * BufferIsValid --
  *		True iff the refcnt of the local buffer is > 0
@@ -155,4 +163,7 @@ extern void BufferRefCountRestore(int *refcountsave);
 extern int	SetBufferWriteMode(int mode);
 extern void SetBufferCommitInfoNeedsSave(Buffer buffer);
 
+extern void UnlockBuffers(void);
+extern void LockBuffer(Buffer buffer, int mode);
+
 #endif	 /* !defined(BufMgrIncluded) */
diff --git a/src/include/storage/ipc.h b/src/include/storage/ipc.h
index 4733b34bbc8..2163aa79d59 100644
--- a/src/include/storage/ipc.h
+++ b/src/include/storage/ipc.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: ipc.h,v 1.30 1998/09/01 04:38:16 momjian Exp $
+ * $Id: ipc.h,v 1.31 1998/12/15 12:46:57 vadim Exp $
  *
  * NOTES
  *	  This file is very architecture-specific.	This stuff should actually
@@ -186,6 +186,8 @@ typedef enum _LockId_
 		((key == PrivateIPCKey) ? key : 11 + (key))
 #define IPCKeyGetWaitIOSemaphoreKey(key) \
 		((key == PrivateIPCKey) ? key : 12 + (key))
+#define IPCKeyGetWaitCLSemaphoreKey(key) \
+		((key == PrivateIPCKey) ? key : 13 + (key))
 
 /* --------------------------
  * NOTE: This macro must always give the highest numbered key as every backend
diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h
index 4082811bcc8..a85ba1e8ff7 100644
--- a/src/include/storage/lmgr.h
+++ b/src/include/storage/lmgr.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: lmgr.h,v 1.15 1998/09/01 04:38:23 momjian Exp $
+ * $Id: lmgr.h,v 1.16 1998/12/15 12:46:57 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,64 +17,48 @@
 #include <utils/rel.h>
 #include <catalog/catname.h>
 
-/*
- * This was moved from pladt.h for the new lock manager.  Want to obsolete
- * all of the old code.
- */
+#define AccessShareLock			1		/* SELECT */
+#define RowShareLock			2		/* SELECT FOR UPDATE */
+#define RowExclusiveLock		3		/* INSERT, UPDATE, DELETE */
+#define ShareLock				4
+#define ShareRowExclusiveLock	5
+#define ExclusiveLock			6
+#define AccessExclusiveLock		7
+
+#define ExtendLock				8
+
+extern LOCKMETHOD LockTableId;
+
+
 typedef struct LockRelId
 {
 	Oid			relId;			/* a relation identifier */
 	Oid			dbId;			/* a database identifier */
 }			LockRelId;
 
-#ifdef LowLevelLocking
 typedef struct LockInfoData
 {
 	LockRelId	lockRelId;
-	bool		lockHeld[MAX_LOCKMODES];		/* on table level */
 } LockInfoData;
 
-#else
-typedef struct LockInfoData
-{
-	LockRelId	lockRelId;
-} LockInfoData;
-
-#endif
-
 typedef LockInfoData *LockInfo;
 
 #define LockInfoIsValid(lockinfo)	PointerIsValid(lockinfo)
 
+extern LOCKMETHOD InitLockTable(void);
 extern void RelationInitLockInfo(Relation relation);
-extern void RelationSetLockForDescriptorOpen(Relation relation);
-extern void RelationSetLockForRead(Relation relation);
-extern void RelationUnsetLockForRead(Relation relation);
-extern void RelationSetLockForWrite(Relation relation);
-extern void RelationUnsetLockForWrite(Relation relation);
 
-/* used in vaccum.c */
-extern void RelationSetLockForWritePage(Relation relation,
-							ItemPointer itemPointer);
+extern void LockRelation(Relation relation, LOCKMODE lockmode);
+extern void UnlockRelation(Relation relation, LOCKMODE lockmode);
 
-/* used in nbtpage.c, hashpage.c */
-extern void RelationSetSingleWLockPage(Relation relation,
-						   ItemPointer itemPointer);
-extern void RelationUnsetSingleWLockPage(Relation relation,
-							 ItemPointer itemPointer);
-extern void RelationSetSingleRLockPage(Relation relation,
-						   ItemPointer itemPointer);
-extern void RelationUnsetSingleRLockPage(Relation relation,
-							 ItemPointer itemPointer);
-extern void RelationSetRIntentLock(Relation relation);
-extern void RelationUnsetRIntentLock(Relation relation);
-extern void RelationSetWIntentLock(Relation relation);
-extern void RelationUnsetWIntentLock(Relation relation);
+/* this is for indices */
+extern void LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode);
+extern void UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode);
 
-/* single.c */
-extern bool SingleLockReln(LockInfo lockinfo, LOCKMODE lockmode, int action);
-extern bool SingleLockPage(LockInfo lockinfo, ItemPointer tidPtr,
-			   LOCKMODE lockmode, int action);
+/* and this is for transactions */
+extern void XactLockTableInsert(TransactionId xid);
+extern void XactLockTableDelete(TransactionId xid);
+extern void XactLockTableWait(TransactionId xid);
 
 /* proc.c */
 extern void InitProcGlobal(IPCKey key);
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index 329aa758a7f..9c803ef8a12 100644
--- a/src/include/storage/lock.h
+++ b/src/include/storage/lock.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: lock.h,v 1.19 1998/10/08 18:30:45 momjian Exp $
+ * $Id: lock.h,v 1.20 1998/12/15 12:46:58 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -42,11 +42,7 @@ typedef int LOCKMODE;
 typedef int LOCKMETHOD;
 
 /* MAX_LOCKMODES cannot be larger than the bits in MASK */
-#ifdef LowLevelLocking
 #define MAX_LOCKMODES	9
-#else
-#define MAX_LOCKMODES	6
-#endif
 
 /*
  * MAX_LOCK_METHODS corresponds to the number of spin locks allocated in
@@ -69,7 +65,11 @@ typedef struct LTAG
 {
 	Oid			relId;
 	Oid			dbId;
-	ItemPointerData tupleId;
+	union
+	{
+		BlockNumber		blkno;
+		TransactionId	xid;
+	}			objId;
 	uint16		lockmethod;		/* needed by user locks */
 } LOCKTAG;
 
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index 4a62fac18ab..914d934524f 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: proc.h,v 1.15 1998/09/01 04:38:31 momjian Exp $
+ * $Id: proc.h,v 1.16 1998/12/15 12:46:59 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -44,11 +44,9 @@ typedef struct proc
 	TransactionId xid;			/* transaction currently being executed by
 								 * this proc */
 
-#ifdef LowLevelLocking
 	TransactionId xmin;			/* minimal running XID as it was when we
 								 * were starting our xact: vacuum must not
 								 * remove tuples deleted by xid >= xmin ! */
-#endif
 
 	LOCK	   *waitLock;		/* Lock we're sleeping on */
 	int			token;			/* info for proc wakeup routines */
diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h
index d47f5ab53b9..aa20a328bdc 100644
--- a/src/include/storage/s_lock.h
+++ b/src/include/storage/s_lock.h
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/include/storage/s_lock.h,v 1.56 1998/10/31 02:06:08 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/include/storage/s_lock.h,v 1.57 1998/12/15 12:46:59 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -68,6 +68,8 @@
 
 #include "storage/ipc.h"
 
+extern void s_lock_sleep(unsigned spin);
+
 #if defined(HAS_TEST_AND_SET)
 
 
diff --git a/src/include/utils/tqual.h b/src/include/utils/tqual.h
index 3d2f8531f47..cb15a60ca0d 100644
--- a/src/include/utils/tqual.h
+++ b/src/include/utils/tqual.h
@@ -7,7 +7,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: tqual.h,v 1.15 1998/11/27 19:33:35 vadim Exp $
+ * $Id: tqual.h,v 1.16 1998/12/15 12:47:01 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,17 +18,20 @@
 
 typedef struct SnapshotData
 {
-	TransactionId xmin;			/* XID < xmin are visible to me */
-	TransactionId xmax;			/* XID > xmax are invisible to me */
-	TransactionId *xip;			/* array of xacts in progress */
+	TransactionId	xmin;			/* XID < xmin are visible to me */
+	TransactionId	xmax;			/* XID > xmax are invisible to me */
+	TransactionId  *xip;			/* array of xacts in progress */
 }			SnapshotData;
 
 typedef SnapshotData *Snapshot;
 
-#define IsSnapshotNow(snapshot)		((Snapshot) snapshot == (Snapshot) 0x0)
-#define IsSnapshotSelf(snapshot)	((Snapshot) snapshot == (Snapshot) 0x1)
 #define SnapshotNow					((Snapshot) 0x0)
 #define SnapshotSelf				((Snapshot) 0x1)
+extern	Snapshot					SnapshotDirty;
+
+#define IsSnapshotNow(snapshot)		((Snapshot) snapshot == SnapshotNow)
+#define IsSnapshotSelf(snapshot)	((Snapshot) snapshot == SnapshotSelf)
+#define IsSnapshotDirty(snapshot)	((Snapshot) snapshot == SnapshotDirty)
 
 extern TransactionId HeapSpecialTransactionId;
 extern CommandId HeapSpecialCommandId;
@@ -49,7 +52,11 @@ extern CommandId HeapSpecialCommandId;
 		(IsSnapshotSelf(snapshot) || heapisoverride()) ? \
 			HeapTupleSatisfiesItself((tuple)->t_data) \
 		: \
-			HeapTupleSatisfiesNow((tuple)->t_data) \
+			((IsSnapshotDirty(snapshot)) ? \
+				HeapTupleSatisfiesDirty((tuple)->t_data) \
+			: \
+				HeapTupleSatisfiesNow((tuple)->t_data) \
+			) \
 	) \
 )
 
@@ -71,10 +78,18 @@ extern CommandId HeapSpecialCommandId;
 	) \
 )
 
-extern bool HeapTupleSatisfiesItself(HeapTupleHeader tuple);
-extern bool HeapTupleSatisfiesNow(HeapTupleHeader tuple);
+#define	HeapTupleMayBeUpdated		0
+#define	HeapTupleInvisible			1
+#define HeapTupleSelfUpdated		2
+#define HeapTupleUpdated			3
+#define HeapTupleBeingUpdated		4
 
-extern void setheapoverride(bool on);
+extern bool		HeapTupleSatisfiesItself(HeapTupleHeader tuple);
+extern bool		HeapTupleSatisfiesNow(HeapTupleHeader tuple);
+extern bool		HeapTupleSatisfiesDirty(HeapTupleHeader tuple);
+extern int		HeapTupleSatisfiesUpdate(HeapTuple tuple);
 
+extern void setheapoverride(bool on);
+extern Snapshot GetSnapshotData(bool serialized);
 
 #endif	 /* TQUAL_H */
-- 
GitLab