*** a/src/backend/access/heap/heapam.c
--- b/src/backend/access/heap/heapam.c
***************
*** 478,484 **** heapgettup(HeapScanDesc scan,
  				if (valid)
  				{
  					if (!scan->rs_relpredicatelocked)
! 						PredicateLockTuple(scan->rs_rd, tuple);
  					LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
  					return;
  				}
--- 478,484 ----
  				if (valid)
  				{
  					if (!scan->rs_relpredicatelocked)
! 						PredicateLockTuple(scan->rs_rd, tuple, snapshot);
  					LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
  					return;
  				}
***************
*** 747,753 **** heapgettup_pagemode(HeapScanDesc scan,
  				if (valid)
  				{
  					if (!scan->rs_relpredicatelocked)
! 						PredicateLockTuple(scan->rs_rd, tuple);
  					scan->rs_cindex = lineindex;
  					return;
  				}
--- 747,753 ----
  				if (valid)
  				{
  					if (!scan->rs_relpredicatelocked)
! 						PredicateLockTuple(scan->rs_rd, tuple, scan->rs_snapshot);
  					scan->rs_cindex = lineindex;
  					return;
  				}
***************
*** 755,761 **** heapgettup_pagemode(HeapScanDesc scan,
  			else
  			{
  				if (!scan->rs_relpredicatelocked)
! 					PredicateLockTuple(scan->rs_rd, tuple);
  				scan->rs_cindex = lineindex;
  				return;
  			}
--- 755,761 ----
  			else
  			{
  				if (!scan->rs_relpredicatelocked)
! 					PredicateLockTuple(scan->rs_rd, tuple, scan->rs_snapshot);
  				scan->rs_cindex = lineindex;
  				return;
  			}
***************
*** 1470,1476 **** heap_fetch(Relation relation,
  	valid = HeapTupleSatisfiesVisibility(tuple, snapshot, buffer);
  
  	if (valid)
! 		PredicateLockTuple(relation, tuple);
  
  	CheckForSerializableConflictOut(valid, relation, tuple, buffer);
  
--- 1470,1476 ----
  	valid = HeapTupleSatisfiesVisibility(tuple, snapshot, buffer);
  
  	if (valid)
! 		PredicateLockTuple(relation, tuple, snapshot);
  
  	CheckForSerializableConflictOut(valid, relation, tuple, buffer);
  
***************
*** 1592,1598 **** heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer,
  		if (valid)
  		{
  			ItemPointerSetOffsetNumber(tid, offnum);
! 			PredicateLockTuple(relation, &heapTuple);
  			if (all_dead)
  				*all_dead = false;
  			return true;
--- 1592,1598 ----
  		if (valid)
  		{
  			ItemPointerSetOffsetNumber(tid, offnum);
! 			PredicateLockTuple(relation, &heapTuple, snapshot);
  			if (all_dead)
  				*all_dead = false;
  			return true;
*** a/src/backend/access/index/indexam.c
--- b/src/backend/access/index/indexam.c
***************
*** 126,132 **** do { \
  } while(0)
  
  static IndexScanDesc index_beginscan_internal(Relation indexRelation,
! 						 int nkeys, int norderbys);
  
  
  /* ----------------------------------------------------------------
--- 126,132 ----
  } while(0)
  
  static IndexScanDesc index_beginscan_internal(Relation indexRelation,
! 						 int nkeys, int norderbys, const Snapshot snapshot);
  
  
  /* ----------------------------------------------------------------
***************
*** 234,240 **** index_beginscan(Relation heapRelation,
  {
  	IndexScanDesc scan;
  
! 	scan = index_beginscan_internal(indexRelation, nkeys, norderbys);
  
  	/*
  	 * Save additional parameters into the scandesc.  Everything else was set
--- 234,240 ----
  {
  	IndexScanDesc scan;
  
! 	scan = index_beginscan_internal(indexRelation, nkeys, norderbys, snapshot);
  
  	/*
  	 * Save additional parameters into the scandesc.  Everything else was set
***************
*** 259,265 **** index_beginscan_bitmap(Relation indexRelation,
  {
  	IndexScanDesc scan;
  
! 	scan = index_beginscan_internal(indexRelation, nkeys, 0);
  
  	/*
  	 * Save additional parameters into the scandesc.  Everything else was set
--- 259,265 ----
  {
  	IndexScanDesc scan;
  
! 	scan = index_beginscan_internal(indexRelation, nkeys, 0, snapshot);
  
  	/*
  	 * Save additional parameters into the scandesc.  Everything else was set
***************
*** 275,281 **** index_beginscan_bitmap(Relation indexRelation,
   */
  static IndexScanDesc
  index_beginscan_internal(Relation indexRelation,
! 						 int nkeys, int norderbys)
  {
  	IndexScanDesc scan;
  	FmgrInfo   *procedure;
--- 275,281 ----
   */
  static IndexScanDesc
  index_beginscan_internal(Relation indexRelation,
! 						 int nkeys, int norderbys, const Snapshot snapshot)
  {
  	IndexScanDesc scan;
  	FmgrInfo   *procedure;
***************
*** 284,290 **** index_beginscan_internal(Relation indexRelation,
  	GET_REL_PROCEDURE(ambeginscan);
  
  	if (!(indexRelation->rd_am->ampredlocks))
! 		PredicateLockRelation(indexRelation);
  
  	/*
  	 * We hold a reference count to the relcache entry throughout the scan.
--- 284,290 ----
  	GET_REL_PROCEDURE(ambeginscan);
  
  	if (!(indexRelation->rd_am->ampredlocks))
! 		PredicateLockRelation(indexRelation, snapshot);
  
  	/*
  	 * We hold a reference count to the relcache entry throughout the scan.
***************
*** 624,630 **** index_getnext(IndexScanDesc scan, ScanDirection direction)
  				else
  					scan->xs_next_hot = InvalidOffsetNumber;
  
! 				PredicateLockTuple(scan->heapRelation, heapTuple);
  
  				LockBuffer(scan->xs_cbuf, BUFFER_LOCK_UNLOCK);
  
--- 624,630 ----
  				else
  					scan->xs_next_hot = InvalidOffsetNumber;
  
! 				PredicateLockTuple(scan->heapRelation, heapTuple, scan->xs_snapshot);
  
  				LockBuffer(scan->xs_cbuf, BUFFER_LOCK_UNLOCK);
  
*** a/src/backend/access/nbtree/nbtsearch.c
--- b/src/backend/access/nbtree/nbtsearch.c
***************
*** 65,71 **** _bt_search(Relation rel, int keysz, ScanKey scankey, bool nextkey,
  	/* If index is empty and access = BT_READ, no root page is created. */
  	if (!BufferIsValid(*bufP))
  	{
! 		PredicateLockRelation(rel);		/* Nothing finer to lock exists. */
  		return (BTStack) NULL;
  	}
  
--- 65,71 ----
  	/* If index is empty and access = BT_READ, no root page is created. */
  	if (!BufferIsValid(*bufP))
  	{
! 		PredicateLockRelation(rel, NULL);		/* Nothing finer to lock exists. */
  		return (BTStack) NULL;
  	}
  
***************
*** 94,100 **** _bt_search(Relation rel, int keysz, ScanKey scankey, bool nextkey,
  		if (P_ISLEAF(opaque))
  		{
  			if (access == BT_READ)
! 				PredicateLockPage(rel, BufferGetBlockNumber(*bufP));
  			break;
  		}
  
--- 94,100 ----
  		if (P_ISLEAF(opaque))
  		{
  			if (access == BT_READ)
! 				PredicateLockPage(rel, BufferGetBlockNumber(*bufP), NULL);
  			break;
  		}
  
***************
*** 1153,1159 **** _bt_steppage(IndexScanDesc scan, ScanDirection dir)
  			opaque = (BTPageOpaque) PageGetSpecialPointer(page);
  			if (!P_IGNORE(opaque))
  			{
! 				PredicateLockPage(rel, blkno);
  				/* see if there are any matches on this page */
  				/* note that this will clear moreRight if we can stop */
  				if (_bt_readpage(scan, dir, P_FIRSTDATAKEY(opaque)))
--- 1153,1159 ----
  			opaque = (BTPageOpaque) PageGetSpecialPointer(page);
  			if (!P_IGNORE(opaque))
  			{
! 				PredicateLockPage(rel, blkno, scan->xs_snapshot);
  				/* see if there are any matches on this page */
  				/* note that this will clear moreRight if we can stop */
  				if (_bt_readpage(scan, dir, P_FIRSTDATAKEY(opaque)))
***************
*** 1201,1207 **** _bt_steppage(IndexScanDesc scan, ScanDirection dir)
  			opaque = (BTPageOpaque) PageGetSpecialPointer(page);
  			if (!P_IGNORE(opaque))
  			{
! 				PredicateLockPage(rel, BufferGetBlockNumber(so->currPos.buf));
  				/* see if there are any matches on this page */
  				/* note that this will clear moreLeft if we can stop */
  				if (_bt_readpage(scan, dir, PageGetMaxOffsetNumber(page)))
--- 1201,1207 ----
  			opaque = (BTPageOpaque) PageGetSpecialPointer(page);
  			if (!P_IGNORE(opaque))
  			{
! 				PredicateLockPage(rel, BufferGetBlockNumber(so->currPos.buf), scan->xs_snapshot);
  				/* see if there are any matches on this page */
  				/* note that this will clear moreLeft if we can stop */
  				if (_bt_readpage(scan, dir, PageGetMaxOffsetNumber(page)))
***************
*** 1365,1371 **** _bt_get_endpoint(Relation rel, uint32 level, bool rightmost)
  	if (!BufferIsValid(buf))
  	{
  		/* empty index... */
! 		PredicateLockRelation(rel);		/* Nothing finer to lock exists. */
  		return InvalidBuffer;
  	}
  
--- 1365,1371 ----
  	if (!BufferIsValid(buf))
  	{
  		/* empty index... */
! 		PredicateLockRelation(rel, NULL);		/* Nothing finer to lock exists. */
  		return InvalidBuffer;
  	}
  
***************
*** 1445,1456 **** _bt_endpoint(IndexScanDesc scan, ScanDirection dir)
  	if (!BufferIsValid(buf))
  	{
  		/* empty index... */
! 		PredicateLockRelation(rel);		/* Nothing finer to lock exists. */
  		so->currPos.buf = InvalidBuffer;
  		return false;
  	}
  
! 	PredicateLockPage(rel, BufferGetBlockNumber(buf));
  	page = BufferGetPage(buf);
  	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
  	Assert(P_ISLEAF(opaque));
--- 1445,1456 ----
  	if (!BufferIsValid(buf))
  	{
  		/* empty index... */
! 		PredicateLockRelation(rel, scan->xs_snapshot);		/* Nothing finer to lock exists. */
  		so->currPos.buf = InvalidBuffer;
  		return false;
  	}
  
! 	PredicateLockPage(rel, BufferGetBlockNumber(buf), scan->xs_snapshot);
  	page = BufferGetPage(buf);
  	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
  	Assert(P_ISLEAF(opaque));
*** a/src/backend/executor/nodeSeqscan.c
--- b/src/backend/executor/nodeSeqscan.c
***************
*** 113,119 **** SeqRecheck(SeqScanState *node, TupleTableSlot *slot)
  TupleTableSlot *
  ExecSeqScan(SeqScanState *node)
  {
! 	PredicateLockRelation(node->ss_currentRelation);
  	node->ss_currentScanDesc->rs_relpredicatelocked = true;
  	return ExecScan((ScanState *) node,
  					(ExecScanAccessMtd) SeqNext,
--- 113,120 ----
  TupleTableSlot *
  ExecSeqScan(SeqScanState *node)
  {
! 	PredicateLockRelation(node->ss_currentRelation,
! 						  node->ss_currentScanDesc->rs_snapshot);
  	node->ss_currentScanDesc->rs_relpredicatelocked = true;
  	return ExecScan((ScanState *) node,
  					(ExecScanAccessMtd) SeqNext,
*** a/src/backend/storage/lmgr/predicate.c
--- b/src/backend/storage/lmgr/predicate.c
***************
*** 148,156 ****
   * predicate lock maintenance
   *		RegisterSerializableTransaction(Snapshot snapshot)
   *		RegisterPredicateLockingXid(void)
!  *		PredicateLockRelation(Relation relation)
!  *		PredicateLockPage(Relation relation, BlockNumber blkno)
!  *		PredicateLockTuple(Relation relation, HeapTuple tuple)
   *		PredicateLockPageSplit(Relation relation, BlockNumber oldblkno,
   *							   BlockNumber newblkno);
   *		PredicateLockPageCombine(Relation relation, BlockNumber oldblkno,
--- 148,158 ----
   * predicate lock maintenance
   *		RegisterSerializableTransaction(Snapshot snapshot)
   *		RegisterPredicateLockingXid(void)
!  *		PredicateLockRelation(Relation relation, Snapshot snapshot)
!  *		PredicateLockPage(Relation relation, BlockNumber blkno,
!  *						Snapshot snapshot)
!  *		PredicateLockTuple(Relation relation, HeapTuple tuple,
!  *						Snapshot snapshot)
   *		PredicateLockPageSplit(Relation relation, BlockNumber oldblkno,
   *							   BlockNumber newblkno);
   *		PredicateLockPageCombine(Relation relation, BlockNumber oldblkno,
***************
*** 271,279 ****
   * the current transaction, this is the test to see if we should do a quick
   * return.
   */
! #define SkipSerialization(relation) \
  	((!IsolationIsSerializable()) \
  	|| ((MySerializableXact == InvalidSerializableXact)) \
  	|| ReleasePredicateLocksIfROSafe() \
  	|| SkipPredicateLocksForRelation(relation))
  
--- 273,282 ----
   * the current transaction, this is the test to see if we should do a quick
   * return.
   */
! #define SkipSerialization(relation, snapshot) \
  	((!IsolationIsSerializable()) \
  	|| ((MySerializableXact == InvalidSerializableXact)) \
+ 	|| ((snapshot) != NULL && !IsMVCCSnapshot(snapshot)) \
  	|| ReleasePredicateLocksIfROSafe() \
  	|| SkipPredicateLocksForRelation(relation))
  
***************
*** 2201,2211 **** PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag)
   * Clear any finer-grained predicate locks this session has on the relation.
   */
  void
! PredicateLockRelation(const Relation relation)
  {
  	PREDICATELOCKTARGETTAG tag;
  
! 	if (SkipSerialization(relation))
  		return;
  
  	SET_PREDICATELOCKTARGETTAG_RELATION(tag,
--- 2204,2214 ----
   * Clear any finer-grained predicate locks this session has on the relation.
   */
  void
! PredicateLockRelation(const Relation relation, const Snapshot snapshot)
  {
  	PREDICATELOCKTARGETTAG tag;
  
! 	if (SkipSerialization(relation, snapshot))
  		return;
  
  	SET_PREDICATELOCKTARGETTAG_RELATION(tag,
***************
*** 2224,2234 **** PredicateLockRelation(const Relation relation)
   * Clear any finer-grained predicate locks this session has on the relation.
   */
  void
! PredicateLockPage(const Relation relation, const BlockNumber blkno)
  {
  	PREDICATELOCKTARGETTAG tag;
  
! 	if (SkipSerialization(relation))
  		return;
  
  	SET_PREDICATELOCKTARGETTAG_PAGE(tag,
--- 2227,2238 ----
   * Clear any finer-grained predicate locks this session has on the relation.
   */
  void
! PredicateLockPage(const Relation relation, const BlockNumber blkno,
! 				  const Snapshot snapshot)
  {
  	PREDICATELOCKTARGETTAG tag;
  
! 	if (SkipSerialization(relation, snapshot))
  		return;
  
  	SET_PREDICATELOCKTARGETTAG_PAGE(tag,
***************
*** 2246,2258 **** PredicateLockPage(const Relation relation, const BlockNumber blkno)
   * Skip if this is a temporary table.
   */
  void
! PredicateLockTuple(const Relation relation, const HeapTuple tuple)
  {
  	PREDICATELOCKTARGETTAG tag;
  	ItemPointer tid;
  	TransactionId targetxmin;
  
! 	if (SkipSerialization(relation))
  		return;
  
  	/*
--- 2250,2263 ----
   * Skip if this is a temporary table.
   */
  void
! PredicateLockTuple(const Relation relation, const HeapTuple tuple,
! 				   const Snapshot snapshot)
  {
  	PREDICATELOCKTARGETTAG tag;
  	ItemPointer tid;
  	TransactionId targetxmin;
  
! 	if (SkipSerialization(relation, snapshot))
  		return;
  
  	/*
***************
*** 3621,3627 **** CheckForSerializableConflictOut(const bool visible, const Relation relation,
  	SERIALIZABLEXACT *sxact;
  	HTSV_Result htsvResult;
  
! 	if (SkipSerialization(relation))
  		return;
  
  	if (SxactIsMarkedForDeath(MySerializableXact))
--- 3626,3632 ----
  	SERIALIZABLEXACT *sxact;
  	HTSV_Result htsvResult;
  
! 	if (SkipSerialization(relation, (Snapshot) NULL))
  		return;
  
  	if (SxactIsMarkedForDeath(MySerializableXact))
***************
*** 3998,4004 **** CheckForSerializableConflictIn(const Relation relation, const HeapTuple tuple,
  {
  	PREDICATELOCKTARGETTAG targettag;
  
! 	if (SkipSerialization(relation))
  		return;
  
  	if (SxactIsMarkedForDeath(MySerializableXact))
--- 4003,4009 ----
  {
  	PREDICATELOCKTARGETTAG targettag;
  
! 	if (SkipSerialization(relation, (Snapshot) NULL))
  		return;
  
  	if (SxactIsMarkedForDeath(MySerializableXact))
***************
*** 4090,4096 **** CheckTableForSerializableConflictIn(const Relation relation)
  	if (!TransactionIdIsValid(PredXact->SxactGlobalXmin))
  		return;
  
! 	if (SkipSerialization(relation))
  		return;
  
  	Assert(relation->rd_index == NULL); /* not an index relation */
--- 4095,4101 ----
  	if (!TransactionIdIsValid(PredXact->SxactGlobalXmin))
  		return;
  
! 	if (SkipSerialization(relation, (Snapshot) NULL))
  		return;
  
  	Assert(relation->rd_index == NULL); /* not an index relation */
*** a/src/include/storage/predicate.h
--- b/src/include/storage/predicate.h
***************
*** 44,52 **** extern bool PageIsPredicateLocked(const Relation relation, const BlockNumber blk
  /* predicate lock maintenance */
  extern Snapshot RegisterSerializableTransaction(Snapshot snapshot);
  extern void RegisterPredicateLockingXid(const TransactionId xid);
! extern void PredicateLockRelation(const Relation relation);
! extern void PredicateLockPage(const Relation relation, const BlockNumber blkno);
! extern void PredicateLockTuple(const Relation relation, const HeapTuple tuple);
  extern void PredicateLockPageSplit(const Relation relation, const BlockNumber oldblkno, const BlockNumber newblkno);
  extern void PredicateLockPageCombine(const Relation relation, const BlockNumber oldblkno, const BlockNumber newblkno);
  extern void TransferPredicateLocksToHeapRelation(const Relation relation);
--- 44,52 ----
  /* predicate lock maintenance */
  extern Snapshot RegisterSerializableTransaction(Snapshot snapshot);
  extern void RegisterPredicateLockingXid(const TransactionId xid);
! extern void PredicateLockRelation(const Relation relation, const Snapshot snapshot);
! extern void PredicateLockPage(const Relation relation, const BlockNumber blkno, const Snapshot snapshot);
! extern void PredicateLockTuple(const Relation relation, const HeapTuple tuple, const Snapshot snapshot);
  extern void PredicateLockPageSplit(const Relation relation, const BlockNumber oldblkno, const BlockNumber newblkno);
  extern void PredicateLockPageCombine(const Relation relation, const BlockNumber oldblkno, const BlockNumber newblkno);
  extern void TransferPredicateLocksToHeapRelation(const Relation relation);
