> > Looks like we have to add checks for the case
> > TransactionIdIsCurrentTransactionId(tuple->t_cmin) when
> > there is HEAP_MOVED_OFF or HEAP_MOVED_IN in t_infomask to
> > all HeapTupleSatisfies* in tqual.c as we do in
> > HeapTupleSatisfiesDirty - note comments about uniq btree-s there.
> 
> Sounds like a plan. Do you want to work on this, or shall I?

Sorry, I'm not able to do this fast enough for current pre-release stage -:(

Vadim

Tue, 18 Dec 2001 11:49:24 -0800
"Mikheev, Vadim" <vmikheev@SECTORBASE.COM>
Re: problems with table corruption continued 
"Mikheev, Vadim" <vmikheev@SECTORBASE.COM> writes:
>> Sounds like a plan. Do you want to work on this, or shall I?

> Sorry, I'm not able to do this fast enough for current pre-release stage -:(

Okay.  I'll work on a patch and send it to you for review, if you like.

			regards, tom lane

Tue, 18 Dec 2001 14:53:53 -0500
Tom Lane <tgl@sss.pgh.pa.us>
Re: problems with table corruption continued 
Okay, I've applied the attached patch to tqual.c.  This brings all the
variants of HeapTupleSatisfies up to speed: I have compared them
carefully and they now all make equivalent series of tests on the tuple
status (though they may interpret the results differently).

I decided that Hiroshi had a good point about testing
TransactionIdIsInProgress, so the code now does that before risking
a change to t_infomask, even in the VACUUM cases.

			regards, tom lane


*** src/backend/utils/time/tqual.c.orig	Mon Oct 29 15:31:08 2001
--- src/backend/utils/time/tqual.c	Wed Dec 19 12:09:32 2001
***************
*** 31,37 ****
  /*
   * HeapTupleSatisfiesItself
   *		True iff heap tuple is valid for "itself."
!  *		"{it}self" means valid as of everything that's happened
   *		in the current transaction, _including_ the current command.
   *
   * Note:
--- 31,37 ----
  /*
   * HeapTupleSatisfiesItself
   *		True iff heap tuple is valid for "itself."
!  *		"itself" means valid as of everything that's happened
   *		in the current transaction, _including_ the current command.
   *
   * Note:
***************
*** 53,59 ****
  bool
  HeapTupleSatisfiesItself(HeapTupleHeader tuple)
  {
- 
  	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
  	{
  		if (tuple->t_infomask & HEAP_XMIN_INVALID)
--- 53,58 ----
***************
*** 61,86 ****
  
  		if (tuple->t_infomask & HEAP_MOVED_OFF)
  		{
! 			if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
! 			{
! 				tuple->t_infomask |= HEAP_XMIN_INVALID;
  				return false;
  			}
  		}
  		else if (tuple->t_infomask & HEAP_MOVED_IN)
  		{
! 			if (!TransactionIdDidCommit((TransactionId) tuple->t_cmin))
  			{
! 				tuple->t_infomask |= HEAP_XMIN_INVALID;
! 				return false;
  			}
  		}
  		else if (TransactionIdIsCurrentTransactionId(tuple->t_xmin))
  		{
  			if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid */
  				return true;
  			if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
  				return true;
  			return false;
  		}
  		else if (!TransactionIdDidCommit(tuple->t_xmin))
--- 60,102 ----
  
  		if (tuple->t_infomask & HEAP_MOVED_OFF)
  		{
! 			if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
  				return false;
+ 			if (!TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
+ 			{
+ 				if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
+ 				{
+ 					tuple->t_infomask |= HEAP_XMIN_INVALID;
+ 					return false;
+ 				}
+ 				tuple->t_infomask |= HEAP_XMIN_COMMITTED;
  			}
  		}
  		else if (tuple->t_infomask & HEAP_MOVED_IN)
  		{
! 			if (!TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
  			{
! 				if (TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
! 					return false;
! 				if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
! 					tuple->t_infomask |= HEAP_XMIN_COMMITTED;
! 				else
! 				{
! 					tuple->t_infomask |= HEAP_XMIN_INVALID;
! 					return false;
! 				}
  			}
  		}
  		else 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;
  		}
  		else if (!TransactionIdDidCommit(tuple->t_xmin))
***************
*** 89,97 ****
  				tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */
  			return false;
  		}
! 		tuple->t_infomask |= HEAP_XMIN_COMMITTED;
  	}
! 	/* the tuple was inserted validly */
  
  	if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid or aborted */
  		return true;
--- 105,115 ----
  				tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */
  			return false;
  		}
! 		else
! 			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;
***************
*** 117,123 ****
  		return true;
  	}
  
! 	/* by here, deleting transaction has committed */
  	tuple->t_infomask |= HEAP_XMAX_COMMITTED;
  
  	if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
--- 135,141 ----
  		return true;
  	}
  
! 	/* xmax transaction committed */
  	tuple->t_infomask |= HEAP_XMAX_COMMITTED;
  
  	if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
***************
*** 177,194 ****
  
  		if (tuple->t_infomask & HEAP_MOVED_OFF)
  		{
! 			if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
! 			{
! 				tuple->t_infomask |= HEAP_XMIN_INVALID;
  				return false;
  			}
  		}
  		else if (tuple->t_infomask & HEAP_MOVED_IN)
  		{
! 			if (!TransactionIdDidCommit((TransactionId) tuple->t_cmin))
  			{
! 				tuple->t_infomask |= HEAP_XMIN_INVALID;
! 				return false;
  			}
  		}
  		else if (TransactionIdIsCurrentTransactionId(tuple->t_xmin))
--- 195,225 ----
  
  		if (tuple->t_infomask & HEAP_MOVED_OFF)
  		{
! 			if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
  				return false;
+ 			if (!TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
+ 			{
+ 				if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
+ 				{
+ 					tuple->t_infomask |= HEAP_XMIN_INVALID;
+ 					return false;
+ 				}
+ 				tuple->t_infomask |= HEAP_XMIN_COMMITTED;
  			}
  		}
  		else if (tuple->t_infomask & HEAP_MOVED_IN)
  		{
! 			if (!TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
  			{
! 				if (TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
! 					return false;
! 				if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
! 					tuple->t_infomask |= HEAP_XMIN_COMMITTED;
! 				else
! 				{
! 					tuple->t_infomask |= HEAP_XMIN_INVALID;
! 					return false;
! 				}
  			}
  		}
  		else if (TransactionIdIsCurrentTransactionId(tuple->t_xmin))
***************
*** 215,221 ****
  				tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */
  			return false;
  		}
! 		tuple->t_infomask |= HEAP_XMIN_COMMITTED;
  	}
  
  	/* by here, the inserting transaction has committed */
--- 246,253 ----
  				tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */
  			return false;
  		}
! 		else
! 			tuple->t_infomask |= HEAP_XMIN_COMMITTED;
  	}
  
  	/* by here, the inserting transaction has committed */
***************
*** 257,348 ****
  }
  
  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 (th->t_infomask & HEAP_MOVED_OFF)
  		{
! 			if (TransactionIdDidCommit((TransactionId) th->t_cmin))
! 			{
! 				th->t_infomask |= HEAP_XMIN_INVALID;
  				return HeapTupleInvisible;
  			}
  		}
! 		else if (th->t_infomask & HEAP_MOVED_IN)
  		{
! 			if (!TransactionIdDidCommit((TransactionId) th->t_cmin))
  			{
! 				th->t_infomask |= HEAP_XMIN_INVALID;
! 				return HeapTupleInvisible;
  			}
  		}
! 		else if (TransactionIdIsCurrentTransactionId(th->t_xmin))
  		{
! 			if (CommandIdGEScanCommandId(th->t_cmin))
  				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 */
  		}
! 		else 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 */
--- 289,394 ----
  }
  
  int
! HeapTupleSatisfiesUpdate(HeapTuple htuple)
  {
! 	HeapTupleHeader tuple = htuple->t_data;
  
  	if (AMI_OVERRIDE)
  		return HeapTupleMayBeUpdated;
  
! 	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
  	{
! 		if (tuple->t_infomask & HEAP_XMIN_INVALID)
  			return HeapTupleInvisible;
  
! 		if (tuple->t_infomask & HEAP_MOVED_OFF)
  		{
! 			if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
  				return HeapTupleInvisible;
+ 			if (!TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
+ 			{
+ 				if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
+ 				{
+ 					tuple->t_infomask |= HEAP_XMIN_INVALID;
+ 					return HeapTupleInvisible;
+ 				}
+ 				tuple->t_infomask |= HEAP_XMIN_COMMITTED;
  			}
  		}
! 		else if (tuple->t_infomask & HEAP_MOVED_IN)
  		{
! 			if (!TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
  			{
! 				if (TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
! 					return HeapTupleInvisible;
! 				if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
! 					tuple->t_infomask |= HEAP_XMIN_COMMITTED;
! 				else
! 				{
! 					tuple->t_infomask |= HEAP_XMIN_INVALID;
! 					return HeapTupleInvisible;
! 				}
  			}
  		}
! 		else if (TransactionIdIsCurrentTransactionId(tuple->t_xmin))
  		{
! 			if (CommandIdGEScanCommandId(tuple->t_cmin))
  				return HeapTupleInvisible;		/* inserted after scan
  												 * started */
  
! 			if (tuple->t_infomask & HEAP_XMAX_INVALID)		/* xid invalid */
  				return HeapTupleMayBeUpdated;
  
! 			Assert(TransactionIdIsCurrentTransactionId(tuple->t_xmax));
  
! 			if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
  				return HeapTupleMayBeUpdated;
  
! 			if (CommandIdGEScanCommandId(tuple->t_cmax))
  				return HeapTupleSelfUpdated;	/* updated after scan
  												 * started */
  			else
  				return HeapTupleInvisible;		/* updated before scan
  												 * started */
  		}
! 		else if (!TransactionIdDidCommit(tuple->t_xmin))
  		{
! 			if (TransactionIdDidAbort(tuple->t_xmin))
! 				tuple->t_infomask |= HEAP_XMIN_INVALID;	/* aborted */
  			return HeapTupleInvisible;
  		}
! 		else
! 			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 HeapTupleMayBeUpdated;
  
! 	if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
  	{
! 		if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
  			return HeapTupleMayBeUpdated;
  		return HeapTupleUpdated;	/* updated by other */
  	}
  
! 	if (TransactionIdIsCurrentTransactionId(tuple->t_xmax))
  	{
! 		if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
  			return HeapTupleMayBeUpdated;
! 		if (CommandIdGEScanCommandId(tuple->t_cmax))
  			return HeapTupleSelfUpdated;		/* updated after scan
  												 * started */
  		else
  			return HeapTupleInvisible;	/* updated before scan started */
  	}
  
! 	if (!TransactionIdDidCommit(tuple->t_xmax))
  	{
! 		if (TransactionIdDidAbort(tuple->t_xmax))
  		{
! 			tuple->t_infomask |= HEAP_XMAX_INVALID;		/* aborted */
  			return HeapTupleMayBeUpdated;
  		}
  		/* running xact */
***************
*** 350,358 ****
  	}
  
  	/* xmax transaction committed */
! 	th->t_infomask |= HEAP_XMAX_COMMITTED;
  
! 	if (th->t_infomask & HEAP_MARKED_FOR_UPDATE)
  		return HeapTupleMayBeUpdated;
  
  	return HeapTupleUpdated;	/* updated by other */
--- 396,404 ----
  	}
  
  	/* xmax transaction committed */
! 	tuple->t_infomask |= HEAP_XMAX_COMMITTED;
  
! 	if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
  		return HeapTupleMayBeUpdated;
  
  	return HeapTupleUpdated;	/* updated by other */
***************
*** 374,396 ****
  
  		if (tuple->t_infomask & HEAP_MOVED_OFF)
  		{
- 			/*
- 			 * HeapTupleSatisfiesDirty is used by unique btree-s and so
- 			 * may be used while vacuuming.
- 			 */
  			if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
  				return false;
! 			if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
  			{
! 				tuple->t_infomask |= HEAP_XMIN_INVALID;
! 				return false;
  			}
- 			tuple->t_infomask |= HEAP_XMIN_COMMITTED;
  		}
  		else if (tuple->t_infomask & HEAP_MOVED_IN)
  		{
  			if (!TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
  			{
  				if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
  					tuple->t_infomask |= HEAP_XMIN_COMMITTED;
  				else
--- 420,443 ----
  
  		if (tuple->t_infomask & HEAP_MOVED_OFF)
  		{
  			if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
  				return false;
! 			if (!TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
  			{
! 				if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
! 				{
! 					tuple->t_infomask |= HEAP_XMIN_INVALID;
! 					return false;
! 				}
! 				tuple->t_infomask |= HEAP_XMIN_COMMITTED;
  			}
  		}
  		else if (tuple->t_infomask & HEAP_MOVED_IN)
  		{
  			if (!TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
  			{
+ 				if (TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
+ 					return false;
  				if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
  					tuple->t_infomask |= HEAP_XMIN_COMMITTED;
  				else
***************
*** 416,425 ****
  		{
  			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 */
  		}
  		else
--- 463,473 ----
  		{
  			if (TransactionIdDidAbort(tuple->t_xmin))
  			{
! 				tuple->t_infomask |= HEAP_XMIN_INVALID;
  				return false;
  			}
  			SnapshotDirty->xmin = tuple->t_xmin;
+ 			/* XXX shouldn't we fall through to look at xmax? */
  			return true;		/* in insertion by other */
  		}
  		else
***************
*** 474,479 ****
--- 522,528 ----
  	if (AMI_OVERRIDE)
  		return true;
  
+ 	/* XXX this is horribly ugly: */
  	if (ReferentialIntegritySnapshotOverride)
  		return HeapTupleSatisfiesNow(tuple);
  
***************
*** 484,501 ****
  
  		if (tuple->t_infomask & HEAP_MOVED_OFF)
  		{
! 			if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
! 			{
! 				tuple->t_infomask |= HEAP_XMIN_INVALID;
  				return false;
  			}
  		}
  		else if (tuple->t_infomask & HEAP_MOVED_IN)
  		{
! 			if (!TransactionIdDidCommit((TransactionId) tuple->t_cmin))
  			{
! 				tuple->t_infomask |= HEAP_XMIN_INVALID;
! 				return false;
  			}
  		}
  		else if (TransactionIdIsCurrentTransactionId(tuple->t_xmin))
--- 533,563 ----
  
  		if (tuple->t_infomask & HEAP_MOVED_OFF)
  		{
! 			if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
  				return false;
+ 			if (!TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
+ 			{
+ 				if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
+ 				{
+ 					tuple->t_infomask |= HEAP_XMIN_INVALID;
+ 					return false;
+ 				}
+ 				tuple->t_infomask |= HEAP_XMIN_COMMITTED;
  			}
  		}
  		else if (tuple->t_infomask & HEAP_MOVED_IN)
  		{
! 			if (!TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
  			{
! 				if (TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
! 					return false;
! 				if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
! 					tuple->t_infomask |= HEAP_XMIN_COMMITTED;
! 				else
! 				{
! 					tuple->t_infomask |= HEAP_XMIN_INVALID;
! 					return false;
! 				}
  			}
  		}
  		else if (TransactionIdIsCurrentTransactionId(tuple->t_xmin))
***************
*** 519,528 ****
  		else if (!TransactionIdDidCommit(tuple->t_xmin))
  		{
  			if (TransactionIdDidAbort(tuple->t_xmin))
! 				tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */
  			return false;
  		}
! 		tuple->t_infomask |= HEAP_XMIN_COMMITTED;
  	}
  
  	/*
--- 581,591 ----
  		else if (!TransactionIdDidCommit(tuple->t_xmin))
  		{
  			if (TransactionIdDidAbort(tuple->t_xmin))
! 				tuple->t_infomask |= HEAP_XMIN_INVALID;
  			return false;
  		}
! 		else
! 			tuple->t_infomask |= HEAP_XMIN_COMMITTED;
  	}
  
  	/*
***************
*** 623,646 ****
  			return HEAPTUPLE_DEAD;
  		else if (tuple->t_infomask & HEAP_MOVED_OFF)
  		{
  			if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
  			{
  				tuple->t_infomask |= HEAP_XMIN_INVALID;
  				return HEAPTUPLE_DEAD;
  			}
- 			/* Assume we can only get here if previous VACUUM aborted, */
- 			/* ie, it couldn't still be in progress */
  			tuple->t_infomask |= HEAP_XMIN_COMMITTED;
  		}
  		else if (tuple->t_infomask & HEAP_MOVED_IN)
  		{
! 			if (!TransactionIdDidCommit((TransactionId) tuple->t_cmin))
  			{
- 				/* Assume we can only get here if previous VACUUM aborted */
  				tuple->t_infomask |= HEAP_XMIN_INVALID;
  				return HEAPTUPLE_DEAD;
  			}
- 			tuple->t_infomask |= HEAP_XMIN_COMMITTED;
  		}
  		else if (TransactionIdIsInProgress(tuple->t_xmin))
  			return HEAPTUPLE_INSERT_IN_PROGRESS;
--- 686,715 ----
  			return HEAPTUPLE_DEAD;
  		else if (tuple->t_infomask & HEAP_MOVED_OFF)
  		{
+ 			if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
+ 				return HEAPTUPLE_DELETE_IN_PROGRESS;
+ 			if (TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
+ 				return HEAPTUPLE_DELETE_IN_PROGRESS;
  			if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
  			{
  				tuple->t_infomask |= HEAP_XMIN_INVALID;
  				return HEAPTUPLE_DEAD;
  			}
  			tuple->t_infomask |= HEAP_XMIN_COMMITTED;
  		}
  		else if (tuple->t_infomask & HEAP_MOVED_IN)
  		{
! 			if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
! 				return HEAPTUPLE_INSERT_IN_PROGRESS;
! 			if (TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
! 				return HEAPTUPLE_INSERT_IN_PROGRESS;
! 			if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
! 				tuple->t_infomask |= HEAP_XMIN_COMMITTED;
! 			else
  			{
  				tuple->t_infomask |= HEAP_XMIN_INVALID;
  				return HEAPTUPLE_DEAD;
  			}
  		}
  		else if (TransactionIdIsInProgress(tuple->t_xmin))
  			return HEAPTUPLE_INSERT_IN_PROGRESS;
***************
*** 671,676 ****
--- 740,751 ----
  	if (tuple->t_infomask & HEAP_XMAX_INVALID)
  		return HEAPTUPLE_LIVE;
  
+ 	if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
+ 	{
+ 		/* "deleting" xact really only marked it for update */
+ 		return HEAPTUPLE_LIVE;
+ 	}
+ 
  	if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
  	{
  		if (TransactionIdIsInProgress(tuple->t_xmax))
***************
*** 698,709 ****
  	/*
  	 * Deleter committed, but check special cases.
  	 */
- 
- 	if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
- 	{
- 		/* "deleting" xact really only marked it for update */
- 		return HEAPTUPLE_LIVE;
- 	}
  
  	if (TransactionIdEquals(tuple->t_xmin, tuple->t_xmax))
  	{
--- 773,778 ----


Wed, 19 Dec 2001 12:23:15 -0500
Tom Lane <tgl@sss.pgh.pa.us>
Re: problems with table corruption continued 