1 /*-------------------------------------------------------------------------
4 * POSTGRES "time" qualification code, ie, tuple visibility rules.
6 * NOTE: all the HeapTupleSatisfies routines will update the tuple's
7 * "hint" status bits if we see that the inserting or deleting transaction
8 * has now committed or aborted. The caller is responsible for noticing any
9 * change in t_infomask and scheduling a disk write if so. Note that the
10 * caller must hold at least a shared buffer context lock on the buffer
11 * containing the tuple. (VACUUM FULL assumes it's sufficient to have
12 * exclusive lock on the containing relation, instead.)
15 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
16 * Portions Copyright (c) 1994, Regents of the University of California
19 * $Header: /cvsroot/pgsql/src/backend/utils/time/tqual.c,v 1.66 2003/08/04 00:43:27 momjian Exp $
21 *-------------------------------------------------------------------------
26 #include "storage/sinval.h"
27 #include "utils/tqual.h"
30 static SnapshotData SnapshotDirtyData;
31 Snapshot SnapshotDirty = &SnapshotDirtyData;
33 static SnapshotData QuerySnapshotData;
34 static SnapshotData SerializableSnapshotData;
35 Snapshot QuerySnapshot = NULL;
36 Snapshot SerializableSnapshot = NULL;
38 /* These are updated by GetSnapshotData: */
39 TransactionId RecentXmin = InvalidTransactionId;
40 TransactionId RecentGlobalXmin = InvalidTransactionId;
42 bool ReferentialIntegritySnapshotOverride = false;
46 * HeapTupleSatisfiesItself
47 * True iff heap tuple is valid "for itself".
49 * Here, we consider the effects of:
50 * all committed transactions (as of the current instant)
51 * previous commands of this transaction
52 * changes made by the current command
55 * Assumes heap tuple is valid.
57 * The satisfaction of "itself" requires the following:
59 * ((Xmin == my-transaction && the row was updated by the current transaction, and
60 * (Xmax is null it was not deleted
61 * [|| Xmax != my-transaction)]) [or it was deleted by another transaction]
64 * (Xmin is committed && the row was modified by a committed transaction, and
65 * (Xmax is null || the row has not been deleted, or
66 * (Xmax != my-transaction && the row was deleted by another transaction
67 * Xmax is not committed))) that has not been committed
70 HeapTupleSatisfiesItself(HeapTupleHeader tuple)
72 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
74 if (tuple->t_infomask & HEAP_XMIN_INVALID)
77 if (tuple->t_infomask & HEAP_MOVED_OFF)
79 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
81 if (TransactionIdIsCurrentTransactionId(xvac))
83 if (!TransactionIdIsInProgress(xvac))
85 if (TransactionIdDidCommit(xvac))
87 tuple->t_infomask |= HEAP_XMIN_INVALID;
90 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
93 else if (tuple->t_infomask & HEAP_MOVED_IN)
95 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
97 if (!TransactionIdIsCurrentTransactionId(xvac))
99 if (TransactionIdIsInProgress(xvac))
101 if (TransactionIdDidCommit(xvac))
102 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
105 tuple->t_infomask |= HEAP_XMIN_INVALID;
110 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
112 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
115 Assert(TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)));
117 if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
122 else if (!TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
124 if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(tuple)))
125 tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */
129 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
132 /* by here, the inserting transaction has committed */
134 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
137 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
139 if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
141 return false; /* updated by other */
144 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
146 if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
151 if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
153 if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple)))
154 tuple->t_infomask |= HEAP_XMAX_INVALID; /* aborted */
158 /* xmax transaction committed */
160 if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
162 tuple->t_infomask |= HEAP_XMAX_INVALID;
166 tuple->t_infomask |= HEAP_XMAX_COMMITTED;
171 * HeapTupleSatisfiesNow
172 * True iff heap tuple is valid "now".
174 * Here, we consider the effects of:
175 * all committed transactions (as of the current instant)
176 * previous commands of this transaction
178 * Note we do _not_ include changes made by the current command. This
179 * solves the "Halloween problem" wherein an UPDATE might try to re-update
180 * its own output tuples.
183 * Assumes heap tuple is valid.
185 * The satisfaction of "now" requires the following:
187 * ((Xmin == my-transaction && changed by the current transaction
188 * Cmin != my-command && but not by this command, and
189 * (Xmax is null || the row has not been deleted, or
190 * (Xmax == my-transaction && it was deleted by the current transaction
191 * Cmax != my-command))) but not by this command,
194 * (Xmin is committed && the row was modified by a committed transaction, and
195 * (Xmax is null || the row has not been deleted, or
196 * (Xmax == my-transaction && the row is being deleted by this command, or
197 * Cmax == my-command) ||
198 * (Xmax is not committed && the row was deleted by another transaction
199 * Xmax != my-transaction)))) that has not been committed
201 * mao says 17 march 1993: the tests in this routine are correct;
202 * if you think they're not, you're wrong, and you should think
203 * about it again. i know, it happened to me. we don't need to
204 * check commit time against the start time of this transaction
205 * because 2ph locking protects us from doing the wrong thing.
206 * if you mess around here, you'll break serializability. the only
207 * problem with this code is that it does the wrong thing for system
208 * catalog updates, because the catalogs aren't subject to 2ph, so
209 * the serializability guarantees we provide don't extend to xacts
210 * that do catalog accesses. this is unfortunate, but not critical.
213 HeapTupleSatisfiesNow(HeapTupleHeader tuple)
215 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
217 if (tuple->t_infomask & HEAP_XMIN_INVALID)
220 if (tuple->t_infomask & HEAP_MOVED_OFF)
222 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
224 if (TransactionIdIsCurrentTransactionId(xvac))
226 if (!TransactionIdIsInProgress(xvac))
228 if (TransactionIdDidCommit(xvac))
230 tuple->t_infomask |= HEAP_XMIN_INVALID;
233 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
236 else if (tuple->t_infomask & HEAP_MOVED_IN)
238 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
240 if (!TransactionIdIsCurrentTransactionId(xvac))
242 if (TransactionIdIsInProgress(xvac))
244 if (TransactionIdDidCommit(xvac))
245 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
248 tuple->t_infomask |= HEAP_XMIN_INVALID;
253 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
255 if (HeapTupleHeaderGetCmin(tuple) >= GetCurrentCommandId())
256 return false; /* inserted after scan started */
258 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
261 Assert(TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)));
263 if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
266 if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId())
267 return true; /* deleted after scan started */
269 return false; /* deleted before scan started */
271 else if (!TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
273 if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(tuple)))
274 tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */
278 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
281 /* by here, the inserting transaction has committed */
283 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
286 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
288 if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
293 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
295 if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
297 if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId())
298 return true; /* deleted after scan started */
300 return false; /* deleted before scan started */
303 if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
305 if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple)))
306 tuple->t_infomask |= HEAP_XMAX_INVALID; /* aborted */
310 /* xmax transaction committed */
312 if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
314 tuple->t_infomask |= HEAP_XMAX_INVALID;
318 tuple->t_infomask |= HEAP_XMAX_COMMITTED;
323 * HeapTupleSatisfiesToast
324 * True iff heap tuple is valid as a TOAST row.
326 * This is a simplified version that only checks for VACUUM moving conditions.
327 * It's appropriate for TOAST usage because TOAST really doesn't want to do
328 * its own time qual checks; if you can see the main table row that contains
329 * a TOAST reference, you should be able to see the TOASTed value. However,
330 * vacuuming a TOAST table is independent of the main table, and in case such
331 * a vacuum fails partway through, we'd better do this much checking.
333 * Among other things, this means you can't do UPDATEs of rows in a TOAST
337 HeapTupleSatisfiesToast(HeapTupleHeader tuple)
339 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
341 if (tuple->t_infomask & HEAP_XMIN_INVALID)
344 if (tuple->t_infomask & HEAP_MOVED_OFF)
346 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
348 if (TransactionIdIsCurrentTransactionId(xvac))
350 if (!TransactionIdIsInProgress(xvac))
352 if (TransactionIdDidCommit(xvac))
354 tuple->t_infomask |= HEAP_XMIN_INVALID;
357 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
360 else if (tuple->t_infomask & HEAP_MOVED_IN)
362 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
364 if (!TransactionIdIsCurrentTransactionId(xvac))
366 if (TransactionIdIsInProgress(xvac))
368 if (TransactionIdDidCommit(xvac))
369 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
372 tuple->t_infomask |= HEAP_XMIN_INVALID;
379 /* otherwise assume the tuple is valid for TOAST. */
384 * HeapTupleSatisfiesUpdate
386 * Same logic as HeapTupleSatisfiesNow, but returns a more detailed result
387 * code, since UPDATE needs to know more than "is it visible?". Also,
388 * tuples of my own xact are tested against the passed CommandId not
392 HeapTupleSatisfiesUpdate(HeapTuple htuple, CommandId curcid)
394 HeapTupleHeader tuple = htuple->t_data;
396 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
398 if (tuple->t_infomask & HEAP_XMIN_INVALID)
399 return HeapTupleInvisible;
401 if (tuple->t_infomask & HEAP_MOVED_OFF)
403 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
405 if (TransactionIdIsCurrentTransactionId(xvac))
406 return HeapTupleInvisible;
407 if (!TransactionIdIsInProgress(xvac))
409 if (TransactionIdDidCommit(xvac))
411 tuple->t_infomask |= HEAP_XMIN_INVALID;
412 return HeapTupleInvisible;
414 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
417 else if (tuple->t_infomask & HEAP_MOVED_IN)
419 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
421 if (!TransactionIdIsCurrentTransactionId(xvac))
423 if (TransactionIdIsInProgress(xvac))
424 return HeapTupleInvisible;
425 if (TransactionIdDidCommit(xvac))
426 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
429 tuple->t_infomask |= HEAP_XMIN_INVALID;
430 return HeapTupleInvisible;
434 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
436 if (HeapTupleHeaderGetCmin(tuple) >= curcid)
437 return HeapTupleInvisible; /* inserted after scan
440 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
441 return HeapTupleMayBeUpdated;
443 Assert(TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)));
445 if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
446 return HeapTupleMayBeUpdated;
448 if (HeapTupleHeaderGetCmax(tuple) >= curcid)
449 return HeapTupleSelfUpdated; /* updated after scan
452 return HeapTupleInvisible; /* updated before scan
455 else if (!TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
457 if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(tuple)))
458 tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */
459 return HeapTupleInvisible;
462 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
465 /* by here, the inserting transaction has committed */
467 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
468 return HeapTupleMayBeUpdated;
470 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
472 if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
473 return HeapTupleMayBeUpdated;
474 return HeapTupleUpdated; /* updated by other */
477 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
479 if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
480 return HeapTupleMayBeUpdated;
481 if (HeapTupleHeaderGetCmax(tuple) >= curcid)
482 return HeapTupleSelfUpdated; /* updated after scan
485 return HeapTupleInvisible; /* updated before scan started */
488 if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
490 if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple)))
492 tuple->t_infomask |= HEAP_XMAX_INVALID; /* aborted */
493 return HeapTupleMayBeUpdated;
496 return HeapTupleBeingUpdated; /* in updation by other */
499 /* xmax transaction committed */
501 if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
503 tuple->t_infomask |= HEAP_XMAX_INVALID;
504 return HeapTupleMayBeUpdated;
507 tuple->t_infomask |= HEAP_XMAX_COMMITTED;
508 return HeapTupleUpdated; /* updated by other */
512 * HeapTupleSatisfiesDirty
513 * True iff heap tuple is valid including effects of open transactions.
515 * Here, we consider the effects of:
516 * all committed and in-progress transactions (as of the current instant)
517 * previous commands of this transaction
518 * changes made by the current command
520 * This is essentially like HeapTupleSatisfiesItself as far as effects of
521 * the current transaction and committed/aborted xacts are concerned.
522 * However, we also include the effects of other xacts still in progress.
524 * Returns extra information in the global variable SnapshotDirty, namely
525 * xids of concurrent xacts that affected the tuple. Also, the tuple's
526 * t_ctid (forward link) is returned if it's being updated.
529 HeapTupleSatisfiesDirty(HeapTupleHeader tuple)
531 SnapshotDirty->xmin = SnapshotDirty->xmax = InvalidTransactionId;
532 ItemPointerSetInvalid(&(SnapshotDirty->tid));
534 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
536 if (tuple->t_infomask & HEAP_XMIN_INVALID)
539 if (tuple->t_infomask & HEAP_MOVED_OFF)
541 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
543 if (TransactionIdIsCurrentTransactionId(xvac))
545 if (!TransactionIdIsInProgress(xvac))
547 if (TransactionIdDidCommit(xvac))
549 tuple->t_infomask |= HEAP_XMIN_INVALID;
552 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
555 else if (tuple->t_infomask & HEAP_MOVED_IN)
557 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
559 if (!TransactionIdIsCurrentTransactionId(xvac))
561 if (TransactionIdIsInProgress(xvac))
563 if (TransactionIdDidCommit(xvac))
564 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
567 tuple->t_infomask |= HEAP_XMIN_INVALID;
572 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
574 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
577 Assert(TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)));
579 if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
584 else if (!TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
586 if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(tuple)))
588 tuple->t_infomask |= HEAP_XMIN_INVALID;
591 SnapshotDirty->xmin = HeapTupleHeaderGetXmin(tuple);
592 /* XXX shouldn't we fall through to look at xmax? */
593 return true; /* in insertion by other */
596 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
599 /* by here, the inserting transaction has committed */
601 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
604 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
606 if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
608 SnapshotDirty->tid = tuple->t_ctid;
609 return false; /* updated by other */
612 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
614 if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
619 if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
621 if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple)))
623 tuple->t_infomask |= HEAP_XMAX_INVALID; /* aborted */
627 SnapshotDirty->xmax = HeapTupleHeaderGetXmax(tuple);
628 return true; /* in updation by other */
631 /* xmax transaction committed */
633 if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
635 tuple->t_infomask |= HEAP_XMAX_INVALID;
639 tuple->t_infomask |= HEAP_XMAX_COMMITTED;
640 SnapshotDirty->tid = tuple->t_ctid;
641 return false; /* updated by other */
645 * HeapTupleSatisfiesSnapshot
646 * True iff heap tuple is valid for the given snapshot.
648 * Here, we consider the effects of:
649 * all transactions committed as of the time of the given snapshot
650 * previous commands of this transaction
652 * Does _not_ include:
653 * transactions shown as in-progress by the snapshot
654 * transactions started after the snapshot was taken
655 * changes made by the current command
657 * This is the same as HeapTupleSatisfiesNow, except that transactions that
658 * were in progress or as yet unstarted when the snapshot was taken will
659 * be treated as uncommitted, even if they have committed by now.
661 * (Notice, however, that the tuple status hint bits will be updated on the
662 * basis of the true state of the transaction, even if we then pretend we
666 HeapTupleSatisfiesSnapshot(HeapTupleHeader tuple, Snapshot snapshot)
668 /* XXX this is horribly ugly: */
669 if (ReferentialIntegritySnapshotOverride)
670 return HeapTupleSatisfiesNow(tuple);
672 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
674 if (tuple->t_infomask & HEAP_XMIN_INVALID)
677 if (tuple->t_infomask & HEAP_MOVED_OFF)
679 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
681 if (TransactionIdIsCurrentTransactionId(xvac))
683 if (!TransactionIdIsInProgress(xvac))
685 if (TransactionIdDidCommit(xvac))
687 tuple->t_infomask |= HEAP_XMIN_INVALID;
690 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
693 else if (tuple->t_infomask & HEAP_MOVED_IN)
695 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
697 if (!TransactionIdIsCurrentTransactionId(xvac))
699 if (TransactionIdIsInProgress(xvac))
701 if (TransactionIdDidCommit(xvac))
702 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
705 tuple->t_infomask |= HEAP_XMIN_INVALID;
710 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
712 if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid)
713 return false; /* inserted after scan started */
715 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
718 Assert(TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)));
720 if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
723 if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
724 return true; /* deleted after scan started */
726 return false; /* deleted before scan started */
728 else if (!TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
730 if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(tuple)))
731 tuple->t_infomask |= HEAP_XMIN_INVALID;
735 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
739 * By here, the inserting transaction has committed - have to check
742 if (TransactionIdFollowsOrEquals(HeapTupleHeaderGetXmin(tuple),
747 if (TransactionIdFollowsOrEquals(HeapTupleHeaderGetXmin(tuple),
751 for (i = 0; i < snapshot->xcnt; i++)
753 if (TransactionIdEquals(HeapTupleHeaderGetXmin(tuple),
759 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
762 if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
765 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
767 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
769 if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
770 return true; /* deleted after scan started */
772 return false; /* deleted before scan started */
775 if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
777 if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple)))
778 tuple->t_infomask |= HEAP_XMAX_INVALID; /* aborted */
782 /* xmax transaction committed */
783 tuple->t_infomask |= HEAP_XMAX_COMMITTED;
787 * OK, the deleting transaction committed too ... but when?
789 if (TransactionIdFollowsOrEquals(HeapTupleHeaderGetXmax(tuple), snapshot->xmin))
793 if (TransactionIdFollowsOrEquals(HeapTupleHeaderGetXmax(tuple),
796 for (i = 0; i < snapshot->xcnt; i++)
798 if (TransactionIdEquals(HeapTupleHeaderGetXmax(tuple), snapshot->xip[i]))
808 * HeapTupleSatisfiesVacuum
810 * Determine the status of tuples for VACUUM purposes. Here, what
811 * we mainly want to know is if a tuple is potentially visible to *any*
812 * running transaction. If so, it can't be removed yet by VACUUM.
814 * OldestXmin is a cutoff XID (obtained from GetOldestXmin()). Tuples
815 * deleted by XIDs >= OldestXmin are deemed "recently dead"; they might
816 * still be visible to some open transaction, so we can't remove them,
817 * even if we see that the deleting transaction has committed.
820 HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin)
823 * Has inserting transaction committed?
825 * If the inserting transaction aborted, then the tuple was never visible
826 * to any other transaction, so we can delete it immediately.
828 * NOTE: must check TransactionIdIsInProgress (which looks in PROC array)
829 * before TransactionIdDidCommit/TransactionIdDidAbort (which look in
830 * pg_clog). Otherwise we have a race condition where we might decide
831 * that a just-committed transaction crashed, because none of the
832 * tests succeed. xact.c is careful to record commit/abort in pg_clog
833 * before it unsets MyProc->xid in PROC array.
835 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
837 if (tuple->t_infomask & HEAP_XMIN_INVALID)
838 return HEAPTUPLE_DEAD;
839 else if (tuple->t_infomask & HEAP_MOVED_OFF)
841 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
843 if (TransactionIdIsCurrentTransactionId(xvac))
844 return HEAPTUPLE_DELETE_IN_PROGRESS;
845 if (TransactionIdIsInProgress(xvac))
846 return HEAPTUPLE_DELETE_IN_PROGRESS;
847 if (TransactionIdDidCommit(xvac))
849 tuple->t_infomask |= HEAP_XMIN_INVALID;
850 return HEAPTUPLE_DEAD;
852 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
854 else if (tuple->t_infomask & HEAP_MOVED_IN)
856 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
858 if (TransactionIdIsCurrentTransactionId(xvac))
859 return HEAPTUPLE_INSERT_IN_PROGRESS;
860 if (TransactionIdIsInProgress(xvac))
861 return HEAPTUPLE_INSERT_IN_PROGRESS;
862 if (TransactionIdDidCommit(xvac))
863 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
866 tuple->t_infomask |= HEAP_XMIN_INVALID;
867 return HEAPTUPLE_DEAD;
870 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
871 return HEAPTUPLE_INSERT_IN_PROGRESS;
872 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
873 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
877 * Not in Progress, Not Committed, so either Aborted or
880 tuple->t_infomask |= HEAP_XMIN_INVALID;
881 return HEAPTUPLE_DEAD;
883 /* Should only get here if we set XMIN_COMMITTED */
884 Assert(tuple->t_infomask & HEAP_XMIN_COMMITTED);
888 * Okay, the inserter committed, so it was good at some point. Now
889 * what about the deleting transaction?
891 if (tuple->t_infomask & HEAP_XMAX_INVALID)
892 return HEAPTUPLE_LIVE;
894 if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
897 * "Deleting" xact really only marked it for update, so the tuple
898 * is live in any case. However, we must make sure that either
899 * XMAX_COMMITTED or XMAX_INVALID gets set once the xact is gone;
900 * otherwise it is unsafe to recycle CLOG status after vacuuming.
902 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
904 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
905 return HEAPTUPLE_LIVE;
908 * We don't really care whether xmax did commit, abort or
909 * crash. We know that xmax did mark the tuple for update, but
910 * it did not and will never actually update it.
912 tuple->t_infomask |= HEAP_XMAX_INVALID;
914 return HEAPTUPLE_LIVE;
917 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
919 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
920 return HEAPTUPLE_DELETE_IN_PROGRESS;
921 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
922 tuple->t_infomask |= HEAP_XMAX_COMMITTED;
926 * Not in Progress, Not Committed, so either Aborted or
929 tuple->t_infomask |= HEAP_XMAX_INVALID;
930 return HEAPTUPLE_LIVE;
932 /* Should only get here if we set XMAX_COMMITTED */
933 Assert(tuple->t_infomask & HEAP_XMAX_COMMITTED);
937 * Deleter committed, but check special cases.
940 if (TransactionIdEquals(HeapTupleHeaderGetXmin(tuple),
941 HeapTupleHeaderGetXmax(tuple)))
944 * inserter also deleted it, so it was never visible to anyone
947 return HEAPTUPLE_DEAD;
950 if (!TransactionIdPrecedes(HeapTupleHeaderGetXmax(tuple), OldestXmin))
952 /* deleting xact is too recent, tuple could still be visible */
953 return HEAPTUPLE_RECENTLY_DEAD;
956 /* Otherwise, it's dead and removable */
957 return HEAPTUPLE_DEAD;
963 * Initialize query snapshot for a new query
965 * The SerializableSnapshot is the first one taken in a transaction.
966 * In serializable mode we just use that one throughout the transaction.
967 * In read-committed mode, we take a new snapshot at the start of each query.
970 SetQuerySnapshot(void)
972 /* Initialize snapshot overriding to false */
973 ReferentialIntegritySnapshotOverride = false;
975 /* 1st call in xaction? */
976 if (SerializableSnapshot == NULL)
978 SerializableSnapshot = GetSnapshotData(&SerializableSnapshotData, true);
979 QuerySnapshot = SerializableSnapshot;
980 Assert(QuerySnapshot != NULL);
984 if (XactIsoLevel == XACT_SERIALIZABLE)
985 QuerySnapshot = SerializableSnapshot;
987 QuerySnapshot = GetSnapshotData(&QuerySnapshotData, false);
989 Assert(QuerySnapshot != NULL);
994 * Copy the current query snapshot.
996 * Copying the snapshot is done so that a query is guaranteed to use a
997 * consistent snapshot for its entire execution life, even if the command
998 * counter is incremented or SetQuerySnapshot() is called while it runs
999 * (as could easily happen, due to triggers etc. executing queries).
1001 * The copy is palloc'd in the current memory context.
1004 CopyQuerySnapshot(void)
1008 if (QuerySnapshot == NULL) /* should be set beforehand */
1009 elog(ERROR, "no snapshot has been set");
1011 snapshot = (Snapshot) palloc(sizeof(SnapshotData));
1012 memcpy(snapshot, QuerySnapshot, sizeof(SnapshotData));
1013 if (snapshot->xcnt > 0)
1015 snapshot->xip = (TransactionId *)
1016 palloc(snapshot->xcnt * sizeof(TransactionId));
1017 memcpy(snapshot->xip, QuerySnapshot->xip,
1018 snapshot->xcnt * sizeof(TransactionId));
1021 snapshot->xip = NULL;
1028 * Free snapshot(s) at end of transaction.
1031 FreeXactSnapshot(void)
1034 * We do not free(QuerySnapshot->xip); or
1035 * free(SerializableSnapshot->xip); they will be reused soon
1037 QuerySnapshot = NULL;
1038 SerializableSnapshot = NULL;