Fix xslt_process() to ensure that it inserts a NULL terminator after the
[PostgreSQL.git] / src / backend / utils / time / tqual.c
bloba73db27c2725200668281564180afd05eda53b8c
1 /*-------------------------------------------------------------------------
3 * tqual.c
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 (and it is safe to set the hint bits).
9 * If the hint bits are changed, SetBufferCommitInfoNeedsSave is called on
10 * the passed-in buffer. The caller must hold not only a pin, but at least
11 * shared buffer content lock on the buffer containing the tuple.
13 * NOTE: must check TransactionIdIsInProgress (which looks in PGPROC array)
14 * before TransactionIdDidCommit/TransactionIdDidAbort (which look in
15 * pg_clog). Otherwise we have a race condition: we might decide that a
16 * just-committed transaction crashed, because none of the tests succeed.
17 * xact.c is careful to record commit/abort in pg_clog before it unsets
18 * MyProc->xid in PGPROC array. That fixes that problem, but it also
19 * means there is a window where TransactionIdIsInProgress and
20 * TransactionIdDidCommit will both return true. If we check only
21 * TransactionIdDidCommit, we could consider a tuple committed when a
22 * later GetSnapshotData call will still think the originating transaction
23 * is in progress, which leads to application-level inconsistency. The
24 * upshot is that we gotta check TransactionIdIsInProgress first in all
25 * code paths, except for a few cases where we are looking at
26 * subtransactions of our own main transaction and so there can't be any
27 * race condition.
29 * Summary of visibility functions:
31 * HeapTupleSatisfiesMVCC()
32 * visible to supplied snapshot, excludes current command
33 * HeapTupleSatisfiesNow()
34 * visible to instant snapshot, excludes current command
35 * HeapTupleSatisfiesUpdate()
36 * like HeapTupleSatisfiesNow(), but with user-supplied command
37 * counter and more complex result
38 * HeapTupleSatisfiesSelf()
39 * visible to instant snapshot and current command
40 * HeapTupleSatisfiesDirty()
41 * like HeapTupleSatisfiesSelf(), but includes open transactions
42 * HeapTupleSatisfiesVacuum()
43 * visible to any running transaction, used by VACUUM
44 * HeapTupleSatisfiesToast()
45 * visible unless part of interrupted vacuum, used for TOAST
46 * HeapTupleSatisfiesAny()
47 * all tuples are visible
49 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
50 * Portions Copyright (c) 1994, Regents of the University of California
52 * IDENTIFICATION
53 * $PostgreSQL$
55 *-------------------------------------------------------------------------
58 #include "postgres.h"
60 #include "access/multixact.h"
61 #include "access/subtrans.h"
62 #include "access/transam.h"
63 #include "access/xact.h"
64 #include "storage/bufmgr.h"
65 #include "storage/procarray.h"
66 #include "utils/tqual.h"
69 /* Static variables representing various special snapshot semantics */
70 SnapshotData SnapshotNowData = {HeapTupleSatisfiesNow};
71 SnapshotData SnapshotSelfData = {HeapTupleSatisfiesSelf};
72 SnapshotData SnapshotAnyData = {HeapTupleSatisfiesAny};
73 SnapshotData SnapshotToastData = {HeapTupleSatisfiesToast};
75 /* local functions */
76 static bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot);
80 * SetHintBits()
82 * Set commit/abort hint bits on a tuple, if appropriate at this time.
84 * It is only safe to set a transaction-committed hint bit if we know the
85 * transaction's commit record has been flushed to disk. We cannot change
86 * the LSN of the page here because we may hold only a share lock on the
87 * buffer, so we can't use the LSN to interlock this; we have to just refrain
88 * from setting the hint bit until some future re-examination of the tuple.
90 * We can always set hint bits when marking a transaction aborted. (Some
91 * code in heapam.c relies on that!)
93 * Also, if we are cleaning up HEAP_MOVED_IN or HEAP_MOVED_OFF entries, then
94 * we can always set the hint bits, since VACUUM FULL always uses synchronous
95 * commits and doesn't move tuples that weren't previously hinted. (This is
96 * not known by this subroutine, but is applied by its callers.)
98 * Normal commits may be asynchronous, so for those we need to get the LSN
99 * of the transaction and then check whether this is flushed.
101 * The caller should pass xid as the XID of the transaction to check, or
102 * InvalidTransactionId if no check is needed.
104 static inline void
105 SetHintBits(HeapTupleHeader tuple, Buffer buffer,
106 uint16 infomask, TransactionId xid)
108 if (TransactionIdIsValid(xid))
110 /* NB: xid must be known committed here! */
111 XLogRecPtr commitLSN = TransactionIdGetCommitLSN(xid);
113 if (XLogNeedsFlush(commitLSN))
114 return; /* not flushed yet, so don't set hint */
117 tuple->t_infomask |= infomask;
118 SetBufferCommitInfoNeedsSave(buffer);
122 * HeapTupleSetHintBits --- exported version of SetHintBits()
124 * This must be separate because of C99's brain-dead notions about how to
125 * implement inline functions.
127 void
128 HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer,
129 uint16 infomask, TransactionId xid)
131 SetHintBits(tuple, buffer, infomask, xid);
136 * HeapTupleSatisfiesSelf
137 * True iff heap tuple is valid "for itself".
139 * Here, we consider the effects of:
140 * all committed transactions (as of the current instant)
141 * previous commands of this transaction
142 * changes made by the current command
144 * Note:
145 * Assumes heap tuple is valid.
147 * The satisfaction of "itself" requires the following:
149 * ((Xmin == my-transaction && the row was updated by the current transaction, and
150 * (Xmax is null it was not deleted
151 * [|| Xmax != my-transaction)]) [or it was deleted by another transaction]
152 * ||
154 * (Xmin is committed && the row was modified by a committed transaction, and
155 * (Xmax is null || the row has not been deleted, or
156 * (Xmax != my-transaction && the row was deleted by another transaction
157 * Xmax is not committed))) that has not been committed
159 bool
160 HeapTupleSatisfiesSelf(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
162 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
164 if (tuple->t_infomask & HEAP_XMIN_INVALID)
165 return false;
167 if (tuple->t_infomask & HEAP_MOVED_OFF)
169 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
171 if (TransactionIdIsCurrentTransactionId(xvac))
172 return false;
173 if (!TransactionIdIsInProgress(xvac))
175 if (TransactionIdDidCommit(xvac))
177 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
178 InvalidTransactionId);
179 return false;
181 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
182 InvalidTransactionId);
185 else if (tuple->t_infomask & HEAP_MOVED_IN)
187 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
189 if (!TransactionIdIsCurrentTransactionId(xvac))
191 if (TransactionIdIsInProgress(xvac))
192 return false;
193 if (TransactionIdDidCommit(xvac))
194 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
195 InvalidTransactionId);
196 else
198 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
199 InvalidTransactionId);
200 return false;
204 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
206 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
207 return true;
209 if (tuple->t_infomask & HEAP_IS_LOCKED) /* not deleter */
210 return true;
212 Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
214 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
216 /* deleting subtransaction must have aborted */
217 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
218 InvalidTransactionId);
219 return true;
222 return false;
224 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
225 return false;
226 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
227 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
228 HeapTupleHeaderGetXmin(tuple));
229 else
231 /* it must have aborted or crashed */
232 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
233 InvalidTransactionId);
234 return false;
238 /* by here, the inserting transaction has committed */
240 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
241 return true;
243 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
245 if (tuple->t_infomask & HEAP_IS_LOCKED)
246 return true;
247 return false; /* updated by other */
250 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
252 /* MultiXacts are currently only allowed to lock tuples */
253 Assert(tuple->t_infomask & HEAP_IS_LOCKED);
254 return true;
257 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
259 if (tuple->t_infomask & HEAP_IS_LOCKED)
260 return true;
261 return false;
264 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
265 return true;
267 if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
269 /* it must have aborted or crashed */
270 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
271 InvalidTransactionId);
272 return true;
275 /* xmax transaction committed */
277 if (tuple->t_infomask & HEAP_IS_LOCKED)
279 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
280 InvalidTransactionId);
281 return true;
284 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
285 HeapTupleHeaderGetXmax(tuple));
286 return false;
290 * HeapTupleSatisfiesNow
291 * True iff heap tuple is valid "now".
293 * Here, we consider the effects of:
294 * all committed transactions (as of the current instant)
295 * previous commands of this transaction
297 * Note we do _not_ include changes made by the current command. This
298 * solves the "Halloween problem" wherein an UPDATE might try to re-update
299 * its own output tuples, http://en.wikipedia.org/wiki/Halloween_Problem.
301 * Note:
302 * Assumes heap tuple is valid.
304 * The satisfaction of "now" requires the following:
306 * ((Xmin == my-transaction && inserted by the current transaction
307 * Cmin < my-command && before this command, and
308 * (Xmax is null || the row has not been deleted, or
309 * (Xmax == my-transaction && it was deleted by the current transaction
310 * Cmax >= my-command))) but not before this command,
311 * || or
312 * (Xmin is committed && the row was inserted by a committed transaction, and
313 * (Xmax is null || the row has not been deleted, or
314 * (Xmax == my-transaction && the row is being deleted by this transaction
315 * Cmax >= my-command) || but it's not deleted "yet", or
316 * (Xmax != my-transaction && the row was deleted by another transaction
317 * Xmax is not committed)))) that has not been committed
319 * mao says 17 march 1993: the tests in this routine are correct;
320 * if you think they're not, you're wrong, and you should think
321 * about it again. i know, it happened to me. we don't need to
322 * check commit time against the start time of this transaction
323 * because 2ph locking protects us from doing the wrong thing.
324 * if you mess around here, you'll break serializability. the only
325 * problem with this code is that it does the wrong thing for system
326 * catalog updates, because the catalogs aren't subject to 2ph, so
327 * the serializability guarantees we provide don't extend to xacts
328 * that do catalog accesses. this is unfortunate, but not critical.
330 bool
331 HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
333 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
335 if (tuple->t_infomask & HEAP_XMIN_INVALID)
336 return false;
338 if (tuple->t_infomask & HEAP_MOVED_OFF)
340 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
342 if (TransactionIdIsCurrentTransactionId(xvac))
343 return false;
344 if (!TransactionIdIsInProgress(xvac))
346 if (TransactionIdDidCommit(xvac))
348 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
349 InvalidTransactionId);
350 return false;
352 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
353 InvalidTransactionId);
356 else if (tuple->t_infomask & HEAP_MOVED_IN)
358 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
360 if (!TransactionIdIsCurrentTransactionId(xvac))
362 if (TransactionIdIsInProgress(xvac))
363 return false;
364 if (TransactionIdDidCommit(xvac))
365 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
366 InvalidTransactionId);
367 else
369 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
370 InvalidTransactionId);
371 return false;
375 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
377 if (HeapTupleHeaderGetCmin(tuple) >= GetCurrentCommandId(false))
378 return false; /* inserted after scan started */
380 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
381 return true;
383 if (tuple->t_infomask & HEAP_IS_LOCKED) /* not deleter */
384 return true;
386 Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
388 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
390 /* deleting subtransaction must have aborted */
391 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
392 InvalidTransactionId);
393 return true;
396 if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId(false))
397 return true; /* deleted after scan started */
398 else
399 return false; /* deleted before scan started */
401 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
402 return false;
403 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
404 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
405 HeapTupleHeaderGetXmin(tuple));
406 else
408 /* it must have aborted or crashed */
409 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
410 InvalidTransactionId);
411 return false;
415 /* by here, the inserting transaction has committed */
417 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
418 return true;
420 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
422 if (tuple->t_infomask & HEAP_IS_LOCKED)
423 return true;
424 return false;
427 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
429 /* MultiXacts are currently only allowed to lock tuples */
430 Assert(tuple->t_infomask & HEAP_IS_LOCKED);
431 return true;
434 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
436 if (tuple->t_infomask & HEAP_IS_LOCKED)
437 return true;
438 if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId(false))
439 return true; /* deleted after scan started */
440 else
441 return false; /* deleted before scan started */
444 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
445 return true;
447 if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
449 /* it must have aborted or crashed */
450 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
451 InvalidTransactionId);
452 return true;
455 /* xmax transaction committed */
457 if (tuple->t_infomask & HEAP_IS_LOCKED)
459 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
460 InvalidTransactionId);
461 return true;
464 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
465 HeapTupleHeaderGetXmax(tuple));
466 return false;
470 * HeapTupleSatisfiesAny
471 * Dummy "satisfies" routine: any tuple satisfies SnapshotAny.
473 bool
474 HeapTupleSatisfiesAny(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
476 return true;
480 * HeapTupleSatisfiesToast
481 * True iff heap tuple is valid as a TOAST row.
483 * This is a simplified version that only checks for VACUUM moving conditions.
484 * It's appropriate for TOAST usage because TOAST really doesn't want to do
485 * its own time qual checks; if you can see the main table row that contains
486 * a TOAST reference, you should be able to see the TOASTed value. However,
487 * vacuuming a TOAST table is independent of the main table, and in case such
488 * a vacuum fails partway through, we'd better do this much checking.
490 * Among other things, this means you can't do UPDATEs of rows in a TOAST
491 * table.
493 bool
494 HeapTupleSatisfiesToast(HeapTupleHeader tuple, Snapshot snapshot,
495 Buffer buffer)
497 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
499 if (tuple->t_infomask & HEAP_XMIN_INVALID)
500 return false;
502 if (tuple->t_infomask & HEAP_MOVED_OFF)
504 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
506 if (TransactionIdIsCurrentTransactionId(xvac))
507 return false;
508 if (!TransactionIdIsInProgress(xvac))
510 if (TransactionIdDidCommit(xvac))
512 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
513 InvalidTransactionId);
514 return false;
516 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
517 InvalidTransactionId);
520 else if (tuple->t_infomask & HEAP_MOVED_IN)
522 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
524 if (!TransactionIdIsCurrentTransactionId(xvac))
526 if (TransactionIdIsInProgress(xvac))
527 return false;
528 if (TransactionIdDidCommit(xvac))
529 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
530 InvalidTransactionId);
531 else
533 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
534 InvalidTransactionId);
535 return false;
541 /* otherwise assume the tuple is valid for TOAST. */
542 return true;
546 * HeapTupleSatisfiesUpdate
548 * Same logic as HeapTupleSatisfiesNow, but returns a more detailed result
549 * code, since UPDATE needs to know more than "is it visible?". Also,
550 * tuples of my own xact are tested against the passed CommandId not
551 * CurrentCommandId.
553 * The possible return codes are:
555 * HeapTupleInvisible: the tuple didn't exist at all when the scan started,
556 * e.g. it was created by a later CommandId.
558 * HeapTupleMayBeUpdated: The tuple is valid and visible, so it may be
559 * updated.
561 * HeapTupleSelfUpdated: The tuple was updated by the current transaction,
562 * after the current scan started.
564 * HeapTupleUpdated: The tuple was updated by a committed transaction.
566 * HeapTupleBeingUpdated: The tuple is being updated by an in-progress
567 * transaction other than the current transaction. (Note: this includes
568 * the case where the tuple is share-locked by a MultiXact, even if the
569 * MultiXact includes the current transaction. Callers that want to
570 * distinguish that case must test for it themselves.)
572 HTSU_Result
573 HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid,
574 Buffer buffer)
576 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
578 if (tuple->t_infomask & HEAP_XMIN_INVALID)
579 return HeapTupleInvisible;
581 if (tuple->t_infomask & HEAP_MOVED_OFF)
583 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
585 if (TransactionIdIsCurrentTransactionId(xvac))
586 return HeapTupleInvisible;
587 if (!TransactionIdIsInProgress(xvac))
589 if (TransactionIdDidCommit(xvac))
591 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
592 InvalidTransactionId);
593 return HeapTupleInvisible;
595 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
596 InvalidTransactionId);
599 else if (tuple->t_infomask & HEAP_MOVED_IN)
601 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
603 if (!TransactionIdIsCurrentTransactionId(xvac))
605 if (TransactionIdIsInProgress(xvac))
606 return HeapTupleInvisible;
607 if (TransactionIdDidCommit(xvac))
608 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
609 InvalidTransactionId);
610 else
612 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
613 InvalidTransactionId);
614 return HeapTupleInvisible;
618 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
620 if (HeapTupleHeaderGetCmin(tuple) >= curcid)
621 return HeapTupleInvisible; /* inserted after scan started */
623 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
624 return HeapTupleMayBeUpdated;
626 if (tuple->t_infomask & HEAP_IS_LOCKED) /* not deleter */
627 return HeapTupleMayBeUpdated;
629 Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
631 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
633 /* deleting subtransaction must have aborted */
634 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
635 InvalidTransactionId);
636 return HeapTupleMayBeUpdated;
639 if (HeapTupleHeaderGetCmax(tuple) >= curcid)
640 return HeapTupleSelfUpdated; /* updated after scan started */
641 else
642 return HeapTupleInvisible; /* updated before scan started */
644 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
645 return HeapTupleInvisible;
646 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
647 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
648 HeapTupleHeaderGetXmin(tuple));
649 else
651 /* it must have aborted or crashed */
652 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
653 InvalidTransactionId);
654 return HeapTupleInvisible;
658 /* by here, the inserting transaction has committed */
660 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
661 return HeapTupleMayBeUpdated;
663 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
665 if (tuple->t_infomask & HEAP_IS_LOCKED)
666 return HeapTupleMayBeUpdated;
667 return HeapTupleUpdated; /* updated by other */
670 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
672 /* MultiXacts are currently only allowed to lock tuples */
673 Assert(tuple->t_infomask & HEAP_IS_LOCKED);
675 if (MultiXactIdIsRunning(HeapTupleHeaderGetXmax(tuple)))
676 return HeapTupleBeingUpdated;
677 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
678 InvalidTransactionId);
679 return HeapTupleMayBeUpdated;
682 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
684 if (tuple->t_infomask & HEAP_IS_LOCKED)
685 return HeapTupleMayBeUpdated;
686 if (HeapTupleHeaderGetCmax(tuple) >= curcid)
687 return HeapTupleSelfUpdated; /* updated after scan started */
688 else
689 return HeapTupleInvisible; /* updated before scan started */
692 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
693 return HeapTupleBeingUpdated;
695 if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
697 /* it must have aborted or crashed */
698 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
699 InvalidTransactionId);
700 return HeapTupleMayBeUpdated;
703 /* xmax transaction committed */
705 if (tuple->t_infomask & HEAP_IS_LOCKED)
707 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
708 InvalidTransactionId);
709 return HeapTupleMayBeUpdated;
712 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
713 HeapTupleHeaderGetXmax(tuple));
714 return HeapTupleUpdated; /* updated by other */
718 * HeapTupleSatisfiesDirty
719 * True iff heap tuple is valid including effects of open transactions.
721 * Here, we consider the effects of:
722 * all committed and in-progress transactions (as of the current instant)
723 * previous commands of this transaction
724 * changes made by the current command
726 * This is essentially like HeapTupleSatisfiesSelf as far as effects of
727 * the current transaction and committed/aborted xacts are concerned.
728 * However, we also include the effects of other xacts still in progress.
730 * A special hack is that the passed-in snapshot struct is used as an
731 * output argument to return the xids of concurrent xacts that affected the
732 * tuple. snapshot->xmin is set to the tuple's xmin if that is another
733 * transaction that's still in progress; or to InvalidTransactionId if the
734 * tuple's xmin is committed good, committed dead, or my own xact. Similarly
735 * for snapshot->xmax and the tuple's xmax.
737 bool
738 HeapTupleSatisfiesDirty(HeapTupleHeader tuple, Snapshot snapshot,
739 Buffer buffer)
741 snapshot->xmin = snapshot->xmax = InvalidTransactionId;
743 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
745 if (tuple->t_infomask & HEAP_XMIN_INVALID)
746 return false;
748 if (tuple->t_infomask & HEAP_MOVED_OFF)
750 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
752 if (TransactionIdIsCurrentTransactionId(xvac))
753 return false;
754 if (!TransactionIdIsInProgress(xvac))
756 if (TransactionIdDidCommit(xvac))
758 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
759 InvalidTransactionId);
760 return false;
762 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
763 InvalidTransactionId);
766 else if (tuple->t_infomask & HEAP_MOVED_IN)
768 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
770 if (!TransactionIdIsCurrentTransactionId(xvac))
772 if (TransactionIdIsInProgress(xvac))
773 return false;
774 if (TransactionIdDidCommit(xvac))
775 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
776 InvalidTransactionId);
777 else
779 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
780 InvalidTransactionId);
781 return false;
785 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
787 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
788 return true;
790 if (tuple->t_infomask & HEAP_IS_LOCKED) /* not deleter */
791 return true;
793 Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
795 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
797 /* deleting subtransaction must have aborted */
798 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
799 InvalidTransactionId);
800 return true;
803 return false;
805 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
807 snapshot->xmin = HeapTupleHeaderGetXmin(tuple);
808 /* XXX shouldn't we fall through to look at xmax? */
809 return true; /* in insertion by other */
811 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
812 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
813 HeapTupleHeaderGetXmin(tuple));
814 else
816 /* it must have aborted or crashed */
817 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
818 InvalidTransactionId);
819 return false;
823 /* by here, the inserting transaction has committed */
825 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
826 return true;
828 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
830 if (tuple->t_infomask & HEAP_IS_LOCKED)
831 return true;
832 return false; /* updated by other */
835 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
837 /* MultiXacts are currently only allowed to lock tuples */
838 Assert(tuple->t_infomask & HEAP_IS_LOCKED);
839 return true;
842 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
844 if (tuple->t_infomask & HEAP_IS_LOCKED)
845 return true;
846 return false;
849 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
851 snapshot->xmax = HeapTupleHeaderGetXmax(tuple);
852 return true;
855 if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
857 /* it must have aborted or crashed */
858 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
859 InvalidTransactionId);
860 return true;
863 /* xmax transaction committed */
865 if (tuple->t_infomask & HEAP_IS_LOCKED)
867 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
868 InvalidTransactionId);
869 return true;
872 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
873 HeapTupleHeaderGetXmax(tuple));
874 return false; /* updated by other */
878 * HeapTupleSatisfiesMVCC
879 * True iff heap tuple is valid for the given MVCC snapshot.
881 * Here, we consider the effects of:
882 * all transactions committed as of the time of the given snapshot
883 * previous commands of this transaction
885 * Does _not_ include:
886 * transactions shown as in-progress by the snapshot
887 * transactions started after the snapshot was taken
888 * changes made by the current command
890 * This is the same as HeapTupleSatisfiesNow, except that transactions that
891 * were in progress or as yet unstarted when the snapshot was taken will
892 * be treated as uncommitted, even if they have committed by now.
894 * (Notice, however, that the tuple status hint bits will be updated on the
895 * basis of the true state of the transaction, even if we then pretend we
896 * can't see it.)
898 bool
899 HeapTupleSatisfiesMVCC(HeapTupleHeader tuple, Snapshot snapshot,
900 Buffer buffer)
902 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
904 if (tuple->t_infomask & HEAP_XMIN_INVALID)
905 return false;
907 if (tuple->t_infomask & HEAP_MOVED_OFF)
909 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
911 if (TransactionIdIsCurrentTransactionId(xvac))
912 return false;
913 if (!TransactionIdIsInProgress(xvac))
915 if (TransactionIdDidCommit(xvac))
917 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
918 InvalidTransactionId);
919 return false;
921 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
922 InvalidTransactionId);
925 else if (tuple->t_infomask & HEAP_MOVED_IN)
927 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
929 if (!TransactionIdIsCurrentTransactionId(xvac))
931 if (TransactionIdIsInProgress(xvac))
932 return false;
933 if (TransactionIdDidCommit(xvac))
934 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
935 InvalidTransactionId);
936 else
938 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
939 InvalidTransactionId);
940 return false;
944 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
946 if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid)
947 return false; /* inserted after scan started */
949 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
950 return true;
952 if (tuple->t_infomask & HEAP_IS_LOCKED) /* not deleter */
953 return true;
955 Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
957 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
959 /* deleting subtransaction must have aborted */
960 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
961 InvalidTransactionId);
962 return true;
965 if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
966 return true; /* deleted after scan started */
967 else
968 return false; /* deleted before scan started */
970 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
971 return false;
972 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
973 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
974 HeapTupleHeaderGetXmin(tuple));
975 else
977 /* it must have aborted or crashed */
978 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
979 InvalidTransactionId);
980 return false;
985 * By here, the inserting transaction has committed - have to check
986 * when...
988 if (XidInMVCCSnapshot(HeapTupleHeaderGetXmin(tuple), snapshot))
989 return false; /* treat as still in progress */
991 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
992 return true;
994 if (tuple->t_infomask & HEAP_IS_LOCKED)
995 return true;
997 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
999 /* MultiXacts are currently only allowed to lock tuples */
1000 Assert(tuple->t_infomask & HEAP_IS_LOCKED);
1001 return true;
1004 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1006 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
1008 if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1009 return true; /* deleted after scan started */
1010 else
1011 return false; /* deleted before scan started */
1014 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
1015 return true;
1017 if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
1019 /* it must have aborted or crashed */
1020 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1021 InvalidTransactionId);
1022 return true;
1025 /* xmax transaction committed */
1026 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1027 HeapTupleHeaderGetXmax(tuple));
1031 * OK, the deleting transaction committed too ... but when?
1033 if (XidInMVCCSnapshot(HeapTupleHeaderGetXmax(tuple), snapshot))
1034 return true; /* treat as still in progress */
1036 return false;
1041 * HeapTupleSatisfiesVacuum
1043 * Determine the status of tuples for VACUUM purposes. Here, what
1044 * we mainly want to know is if a tuple is potentially visible to *any*
1045 * running transaction. If so, it can't be removed yet by VACUUM.
1047 * OldestXmin is a cutoff XID (obtained from GetOldestXmin()). Tuples
1048 * deleted by XIDs >= OldestXmin are deemed "recently dead"; they might
1049 * still be visible to some open transaction, so we can't remove them,
1050 * even if we see that the deleting transaction has committed.
1052 HTSV_Result
1053 HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin,
1054 Buffer buffer)
1057 * Has inserting transaction committed?
1059 * If the inserting transaction aborted, then the tuple was never visible
1060 * to any other transaction, so we can delete it immediately.
1062 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
1064 if (tuple->t_infomask & HEAP_XMIN_INVALID)
1065 return HEAPTUPLE_DEAD;
1066 else if (tuple->t_infomask & HEAP_MOVED_OFF)
1068 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
1070 if (TransactionIdIsCurrentTransactionId(xvac))
1071 return HEAPTUPLE_DELETE_IN_PROGRESS;
1072 if (TransactionIdIsInProgress(xvac))
1073 return HEAPTUPLE_DELETE_IN_PROGRESS;
1074 if (TransactionIdDidCommit(xvac))
1076 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1077 InvalidTransactionId);
1078 return HEAPTUPLE_DEAD;
1080 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1081 InvalidTransactionId);
1083 else if (tuple->t_infomask & HEAP_MOVED_IN)
1085 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
1087 if (TransactionIdIsCurrentTransactionId(xvac))
1088 return HEAPTUPLE_INSERT_IN_PROGRESS;
1089 if (TransactionIdIsInProgress(xvac))
1090 return HEAPTUPLE_INSERT_IN_PROGRESS;
1091 if (TransactionIdDidCommit(xvac))
1092 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1093 InvalidTransactionId);
1094 else
1096 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1097 InvalidTransactionId);
1098 return HEAPTUPLE_DEAD;
1101 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
1103 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
1104 return HEAPTUPLE_INSERT_IN_PROGRESS;
1105 if (tuple->t_infomask & HEAP_IS_LOCKED)
1106 return HEAPTUPLE_INSERT_IN_PROGRESS;
1107 /* inserted and then deleted by same xact */
1108 return HEAPTUPLE_DELETE_IN_PROGRESS;
1110 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
1111 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1112 HeapTupleHeaderGetXmin(tuple));
1113 else
1116 * Not in Progress, Not Committed, so either Aborted or crashed
1118 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1119 InvalidTransactionId);
1120 return HEAPTUPLE_DEAD;
1124 * At this point the xmin is known committed, but we might not have
1125 * been able to set the hint bit yet; so we can no longer Assert that
1126 * it's set.
1131 * Okay, the inserter committed, so it was good at some point. Now what
1132 * about the deleting transaction?
1134 if (tuple->t_infomask & HEAP_XMAX_INVALID)
1135 return HEAPTUPLE_LIVE;
1137 if (tuple->t_infomask & HEAP_IS_LOCKED)
1140 * "Deleting" xact really only locked it, so the tuple is live in any
1141 * case. However, we should make sure that either XMAX_COMMITTED or
1142 * XMAX_INVALID gets set once the xact is gone, to reduce the costs of
1143 * examining the tuple for future xacts. Also, marking dead
1144 * MultiXacts as invalid here provides defense against MultiXactId
1145 * wraparound (see also comments in heap_freeze_tuple()).
1147 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1149 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1151 if (MultiXactIdIsRunning(HeapTupleHeaderGetXmax(tuple)))
1152 return HEAPTUPLE_LIVE;
1154 else
1156 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
1157 return HEAPTUPLE_LIVE;
1161 * We don't really care whether xmax did commit, abort or crash.
1162 * We know that xmax did lock the tuple, but it did not and will
1163 * never actually update it.
1165 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1166 InvalidTransactionId);
1168 return HEAPTUPLE_LIVE;
1171 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1173 /* MultiXacts are currently only allowed to lock tuples */
1174 Assert(tuple->t_infomask & HEAP_IS_LOCKED);
1175 return HEAPTUPLE_LIVE;
1178 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1180 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
1181 return HEAPTUPLE_DELETE_IN_PROGRESS;
1182 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
1183 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1184 HeapTupleHeaderGetXmax(tuple));
1185 else
1188 * Not in Progress, Not Committed, so either Aborted or crashed
1190 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1191 InvalidTransactionId);
1192 return HEAPTUPLE_LIVE;
1196 * At this point the xmax is known committed, but we might not have
1197 * been able to set the hint bit yet; so we can no longer Assert that
1198 * it's set.
1203 * Deleter committed, but check special cases.
1206 if (TransactionIdEquals(HeapTupleHeaderGetXmin(tuple),
1207 HeapTupleHeaderGetXmax(tuple)))
1210 * Inserter also deleted it, so it was never visible to anyone else.
1211 * However, we can only remove it early if it's not an updated tuple;
1212 * else its parent tuple is linking to it via t_ctid, and this tuple
1213 * mustn't go away before the parent does.
1215 if (!(tuple->t_infomask & HEAP_UPDATED))
1216 return HEAPTUPLE_DEAD;
1219 if (!TransactionIdPrecedes(HeapTupleHeaderGetXmax(tuple), OldestXmin))
1221 /* deleting xact is too recent, tuple could still be visible */
1222 return HEAPTUPLE_RECENTLY_DEAD;
1225 /* Otherwise, it's dead and removable */
1226 return HEAPTUPLE_DEAD;
1231 * XidInMVCCSnapshot
1232 * Is the given XID still-in-progress according to the snapshot?
1234 * Note: GetSnapshotData never stores either top xid or subxids of our own
1235 * backend into a snapshot, so these xids will not be reported as "running"
1236 * by this function. This is OK for current uses, because we actually only
1237 * apply this for known-committed XIDs.
1239 static bool
1240 XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot)
1242 uint32 i;
1245 * Make a quick range check to eliminate most XIDs without looking at the
1246 * xip arrays. Note that this is OK even if we convert a subxact XID to
1247 * its parent below, because a subxact with XID < xmin has surely also got
1248 * a parent with XID < xmin, while one with XID >= xmax must belong to a
1249 * parent that was not yet committed at the time of this snapshot.
1252 /* Any xid < xmin is not in-progress */
1253 if (TransactionIdPrecedes(xid, snapshot->xmin))
1254 return false;
1255 /* Any xid >= xmax is in-progress */
1256 if (TransactionIdFollowsOrEquals(xid, snapshot->xmax))
1257 return true;
1260 * If the snapshot contains full subxact data, the fastest way to check
1261 * things is just to compare the given XID against both subxact XIDs and
1262 * top-level XIDs. If the snapshot overflowed, we have to use pg_subtrans
1263 * to convert a subxact XID to its parent XID, but then we need only look
1264 * at top-level XIDs not subxacts.
1266 if (snapshot->subxcnt >= 0)
1268 /* full data, so search subxip */
1269 int32 j;
1271 for (j = 0; j < snapshot->subxcnt; j++)
1273 if (TransactionIdEquals(xid, snapshot->subxip[j]))
1274 return true;
1277 /* not there, fall through to search xip[] */
1279 else
1281 /* overflowed, so convert xid to top-level */
1282 xid = SubTransGetTopmostTransaction(xid);
1285 * If xid was indeed a subxact, we might now have an xid < xmin, so
1286 * recheck to avoid an array scan. No point in rechecking xmax.
1288 if (TransactionIdPrecedes(xid, snapshot->xmin))
1289 return false;
1292 for (i = 0; i < snapshot->xcnt; i++)
1294 if (TransactionIdEquals(xid, snapshot->xip[i]))
1295 return true;
1298 return false;