summaryrefslogtreecommitdiff
path: root/src/backend/utils/time/tqual.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/time/tqual.c')
-rw-r--r--src/backend/utils/time/tqual.c1019
1 files changed, 0 insertions, 1019 deletions
diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c
deleted file mode 100644
index 601208ec259..00000000000
--- a/src/backend/utils/time/tqual.c
+++ /dev/null
@@ -1,1019 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * tqual.c
- * POSTGRES "time" qualification code, ie, tuple visibility rules.
- *
- * NOTE: all the HeapTupleSatisfies routines will update the tuple's
- * "hint" status bits if we see that the inserting or deleting transaction
- * has now committed or aborted. The caller is responsible for noticing any
- * change in t_infomask and scheduling a disk write if so. Note that the
- * caller must hold at least a shared buffer context lock on the buffer
- * containing the tuple. (VACUUM FULL assumes it's sufficient to have
- * exclusive lock on the containing relation, instead.)
- *
- *
- * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/time/tqual.c,v 1.56 2002/06/20 20:29:41 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-
-#include "postgres.h"
-
-#include "storage/sinval.h"
-#include "utils/tqual.h"
-
-
-static SnapshotData SnapshotDirtyData;
-Snapshot SnapshotDirty = &SnapshotDirtyData;
-
-Snapshot QuerySnapshot = NULL;
-Snapshot SerializableSnapshot = NULL;
-
-/* This is updated by GetSnapshotData: */
-TransactionId RecentGlobalXmin = InvalidTransactionId;
-
-bool ReferentialIntegritySnapshotOverride = false;
-
-
-/*
- * HeapTupleSatisfiesItself
- * True iff heap tuple is valid "for itself".
- *
- * Here, we consider the effects of:
- * all committed transactions (as of the current instant)
- * previous commands of this transaction
- * changes made by the current command
- *
- * Note:
- * Assumes heap tuple is valid.
- *
- * The satisfaction of "itself" requires the following:
- *
- * ((Xmin == my-transaction && the row was updated by the current transaction, and
- * (Xmax is null it was not deleted
- * [|| Xmax != my-transaction)]) [or it was deleted by another transaction]
- * ||
- *
- * (Xmin is committed && the row was modified by a committed transaction, and
- * (Xmax is null || the row has not been deleted, or
- * (Xmax != my-transaction && the row was deleted by another transaction
- * Xmax is not committed))) that has not been committed
- */
-bool
-HeapTupleSatisfiesItself(HeapTupleHeader tuple)
-{
- if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
- {
- if (tuple->t_infomask & HEAP_XMIN_INVALID)
- return false;
-
- if (tuple->t_infomask & HEAP_MOVED_OFF)
- {
- if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXvac(tuple)))
- return false;
- if (!TransactionIdIsInProgress(HeapTupleHeaderGetXvac(tuple)))
- {
- if (TransactionIdDidCommit(HeapTupleHeaderGetXvac(tuple)))
- {
- tuple->t_infomask |= HEAP_XMIN_INVALID;
- return false;
- }
- tuple->t_infomask |= HEAP_XMIN_COMMITTED;
- }
- }
- else if (tuple->t_infomask & HEAP_MOVED_IN)
- {
- if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXvac(tuple)))
- {
- if (TransactionIdIsInProgress(HeapTupleHeaderGetXvac(tuple)))
- return false;
- if (TransactionIdDidCommit(HeapTupleHeaderGetXvac(tuple)))
- tuple->t_infomask |= HEAP_XMIN_COMMITTED;
- else
- {
- tuple->t_infomask |= HEAP_XMIN_INVALID;
- return false;
- }
- }
- }
- else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
- {
- if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
- return true;
-
- Assert(TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)));
-
- if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
- return true;
-
- return false;
- }
- else if (!TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
- {
- if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(tuple)))
- 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;
-
- if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
- {
- if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
- return true;
- return false; /* updated by other */
- }
-
- if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
- {
- if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
- return true;
- return false;
- }
-
- if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
- {
- if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple)))
- tuple->t_infomask |= HEAP_XMAX_INVALID; /* aborted */
- return true;
- }
-
- /* xmax transaction committed */
- tuple->t_infomask |= HEAP_XMAX_COMMITTED;
-
- if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
- return true;
-
- return false;
-}
-
-/*
- * HeapTupleSatisfiesNow
- * True iff heap tuple is valid "now".
- *
- * Here, we consider the effects of:
- * all committed transactions (as of the current instant)
- * previous commands of this transaction
- *
- * Note we do _not_ include changes made by the current command. This
- * solves the "Halloween problem" wherein an UPDATE might try to re-update
- * its own output tuples.
- *
- * Note:
- * Assumes heap tuple is valid.
- *
- * The satisfaction of "now" requires the following:
- *
- * ((Xmin == my-transaction && changed by the current transaction
- * Cmin != my-command && but not by this command, and
- * (Xmax is null || the row has not been deleted, or
- * (Xmax == my-transaction && it was deleted by the current transaction
- * Cmax != my-command))) but not by this command,
- * || or
- *
- * (Xmin is committed && the row was modified by a committed transaction, and
- * (Xmax is null || the row has not been deleted, or
- * (Xmax == my-transaction && the row is being deleted by this command, or
- * Cmax == my-command) ||
- * (Xmax is not committed && the row was deleted by another transaction
- * Xmax != my-transaction)))) that has not been committed
- *
- * mao says 17 march 1993: the tests in this routine are correct;
- * if you think they're not, you're wrong, and you should think
- * about it again. i know, it happened to me. we don't need to
- * check commit time against the start time of this transaction
- * because 2ph locking protects us from doing the wrong thing.
- * if you mess around here, you'll break serializability. the only
- * problem with this code is that it does the wrong thing for system
- * catalog updates, because the catalogs aren't subject to 2ph, so
- * the serializability guarantees we provide don't extend to xacts
- * that do catalog accesses. this is unfortunate, but not critical.
- */
-bool
-HeapTupleSatisfiesNow(HeapTupleHeader tuple)
-{
- if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
- {
- if (tuple->t_infomask & HEAP_XMIN_INVALID)
- return false;
-
- if (tuple->t_infomask & HEAP_MOVED_OFF)
- {
- if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXvac(tuple)))
- return false;
- if (!TransactionIdIsInProgress(HeapTupleHeaderGetXvac(tuple)))
- {
- if (TransactionIdDidCommit(HeapTupleHeaderGetXvac(tuple)))
- {
- tuple->t_infomask |= HEAP_XMIN_INVALID;
- return false;
- }
- tuple->t_infomask |= HEAP_XMIN_COMMITTED;
- }
- }
- else if (tuple->t_infomask & HEAP_MOVED_IN)
- {
- if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXvac(tuple)))
- {
- if (TransactionIdIsInProgress(HeapTupleHeaderGetXvac(tuple)))
- return false;
- if (TransactionIdDidCommit(HeapTupleHeaderGetXvac(tuple)))
- tuple->t_infomask |= HEAP_XMIN_COMMITTED;
- else
- {
- tuple->t_infomask |= HEAP_XMIN_INVALID;
- return false;
- }
- }
- }
- else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
- {
- if (HeapTupleHeaderGetCmin(tuple) >= GetCurrentCommandId())
- return false; /* inserted after scan started */
-
- if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
- return true;
-
- Assert(TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)));
-
- if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
- return true;
-
- if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId())
- return true; /* deleted after scan started */
- else
- return false; /* deleted before scan started */
- }
- else if (!TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
- {
- if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(tuple)))
- 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;
-
- if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
- {
- if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
- return true;
- return false;
- }
-
- if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
- {
- if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
- return true;
- if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId())
- return true; /* deleted after scan started */
- else
- return false; /* deleted before scan started */
- }
-
- if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
- {
- if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple)))
- tuple->t_infomask |= HEAP_XMAX_INVALID; /* aborted */
- return true;
- }
-
- /* xmax transaction committed */
- tuple->t_infomask |= HEAP_XMAX_COMMITTED;
-
- if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
- return true;
-
- return false;
-}
-
-/*
- * HeapTupleSatisfiesToast
- * True iff heap tuple is valid as a TOAST row.
- *
- * This is a simplified version that only checks for VACUUM moving conditions.
- * It's appropriate for TOAST usage because TOAST really doesn't want to do
- * its own time qual checks; if you can see the main table row that contains
- * a TOAST reference, you should be able to see the TOASTed value. However,
- * vacuuming a TOAST table is independent of the main table, and in case such
- * a vacuum fails partway through, we'd better do this much checking.
- *
- * Among other things, this means you can't do UPDATEs of rows in a TOAST
- * table.
- */
-bool
-HeapTupleSatisfiesToast(HeapTupleHeader tuple)
-{
- if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
- {
- if (tuple->t_infomask & HEAP_XMIN_INVALID)
- return false;
-
- if (tuple->t_infomask & HEAP_MOVED_OFF)
- {
- if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXvac(tuple)))
- return false;
- if (!TransactionIdIsInProgress(HeapTupleHeaderGetXvac(tuple)))
- {
- if (TransactionIdDidCommit(HeapTupleHeaderGetXvac(tuple)))
- {
- tuple->t_infomask |= HEAP_XMIN_INVALID;
- return false;
- }
- tuple->t_infomask |= HEAP_XMIN_COMMITTED;
- }
- }
- else if (tuple->t_infomask & HEAP_MOVED_IN)
- {
- if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXvac(tuple)))
- {
- if (TransactionIdIsInProgress(HeapTupleHeaderGetXvac(tuple)))
- return false;
- if (TransactionIdDidCommit(HeapTupleHeaderGetXvac(tuple)))
- tuple->t_infomask |= HEAP_XMIN_COMMITTED;
- else
- {
- tuple->t_infomask |= HEAP_XMIN_INVALID;
- return false;
- }
- }
- }
- }
-
- /* otherwise assume the tuple is valid for TOAST. */
- return true;
-}
-
-/*
- * HeapTupleSatisfiesUpdate
- *
- * Same logic as HeapTupleSatisfiesNow, but returns a more detailed result
- * code, since UPDATE needs to know more than "is it visible?". Also,
- * tuples of my own xact are tested against the passed CommandId not
- * CurrentCommandId.
- */
-int
-HeapTupleSatisfiesUpdate(HeapTuple htuple, CommandId curcid)
-{
- HeapTupleHeader tuple = htuple->t_data;
-
- 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(HeapTupleHeaderGetXvac(tuple)))
- return HeapTupleInvisible;
- if (!TransactionIdIsInProgress(HeapTupleHeaderGetXvac(tuple)))
- {
- if (TransactionIdDidCommit(HeapTupleHeaderGetXvac(tuple)))
- {
- tuple->t_infomask |= HEAP_XMIN_INVALID;
- return HeapTupleInvisible;
- }
- tuple->t_infomask |= HEAP_XMIN_COMMITTED;
- }
- }
- else if (tuple->t_infomask & HEAP_MOVED_IN)
- {
- if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXvac(tuple)))
- {
- if (TransactionIdIsInProgress(HeapTupleHeaderGetXvac(tuple)))
- return HeapTupleInvisible;
- if (TransactionIdDidCommit(HeapTupleHeaderGetXvac(tuple)))
- tuple->t_infomask |= HEAP_XMIN_COMMITTED;
- else
- {
- tuple->t_infomask |= HEAP_XMIN_INVALID;
- return HeapTupleInvisible;
- }
- }
- }
- else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
- {
- if (HeapTupleHeaderGetCmin(tuple) >= curcid)
- return HeapTupleInvisible; /* inserted after scan
- * started */
-
- if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
- return HeapTupleMayBeUpdated;
-
- Assert(TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)));
-
- if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
- return HeapTupleMayBeUpdated;
-
- if (HeapTupleHeaderGetCmax(tuple) >= curcid)
- return HeapTupleSelfUpdated; /* updated after scan
- * started */
- else
- return HeapTupleInvisible; /* updated before scan
- * started */
- }
- else if (!TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
- {
- if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(tuple)))
- 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(HeapTupleHeaderGetXmax(tuple)))
- {
- if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
- return HeapTupleMayBeUpdated;
- if (HeapTupleHeaderGetCmax(tuple) >= curcid)
- return HeapTupleSelfUpdated; /* updated after scan
- * started */
- else
- return HeapTupleInvisible; /* updated before scan started */
- }
-
- if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
- {
- if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple)))
- {
- tuple->t_infomask |= HEAP_XMAX_INVALID; /* aborted */
- return HeapTupleMayBeUpdated;
- }
- /* running xact */
- return HeapTupleBeingUpdated; /* in updation by other */
- }
-
- /* xmax transaction committed */
- tuple->t_infomask |= HEAP_XMAX_COMMITTED;
-
- if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
- return HeapTupleMayBeUpdated;
-
- return HeapTupleUpdated; /* updated by other */
-}
-
-/*
- * HeapTupleSatisfiesDirty
- * True iff heap tuple is valid including effects of open transactions.
- *
- * Here, we consider the effects of:
- * all committed and in-progress transactions (as of the current instant)
- * previous commands of this transaction
- * changes made by the current command
- *
- * This is essentially like HeapTupleSatisfiesItself as far as effects of
- * the current transaction and committed/aborted xacts are concerned.
- * However, we also include the effects of other xacts still in progress.
- *
- * Returns extra information in the global variable SnapshotDirty, namely
- * xids of concurrent xacts that affected the tuple. Also, the tuple's
- * t_ctid (forward link) is returned if it's being updated.
- */
-bool
-HeapTupleSatisfiesDirty(HeapTupleHeader tuple)
-{
- SnapshotDirty->xmin = SnapshotDirty->xmax = InvalidTransactionId;
- ItemPointerSetInvalid(&(SnapshotDirty->tid));
-
- if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
- {
- if (tuple->t_infomask & HEAP_XMIN_INVALID)
- return false;
-
- if (tuple->t_infomask & HEAP_MOVED_OFF)
- {
- if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXvac(tuple)))
- return false;
- if (!TransactionIdIsInProgress(HeapTupleHeaderGetXvac(tuple)))
- {
- if (TransactionIdDidCommit(HeapTupleHeaderGetXvac(tuple)))
- {
- tuple->t_infomask |= HEAP_XMIN_INVALID;
- return false;
- }
- tuple->t_infomask |= HEAP_XMIN_COMMITTED;
- }
- }
- else if (tuple->t_infomask & HEAP_MOVED_IN)
- {
- if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXvac(tuple)))
- {
- if (TransactionIdIsInProgress(HeapTupleHeaderGetXvac(tuple)))
- return false;
- if (TransactionIdDidCommit(HeapTupleHeaderGetXvac(tuple)))
- tuple->t_infomask |= HEAP_XMIN_COMMITTED;
- else
- {
- tuple->t_infomask |= HEAP_XMIN_INVALID;
- return false;
- }
- }
- }
- else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
- {
- if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
- return true;
-
- Assert(TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)));
-
- if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
- return true;
-
- return false;
- }
- else if (!TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
- {
- if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(tuple)))
- {
- tuple->t_infomask |= HEAP_XMIN_INVALID;
- return false;
- }
- SnapshotDirty->xmin = HeapTupleHeaderGetXmin(tuple);
- /* XXX shouldn't we fall through to look at xmax? */
- return true; /* in insertion by other */
- }
- 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;
-
- if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
- {
- if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
- return true;
- SnapshotDirty->tid = tuple->t_ctid;
- return false; /* updated by other */
- }
-
- if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
- {
- if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
- return true;
- return false;
- }
-
- if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
- {
- if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple)))
- {
- tuple->t_infomask |= HEAP_XMAX_INVALID; /* aborted */
- return true;
- }
- /* running xact */
- SnapshotDirty->xmax = HeapTupleHeaderGetXmax(tuple);
- return true; /* in updation by other */
- }
-
- /* xmax transaction committed */
- tuple->t_infomask |= HEAP_XMAX_COMMITTED;
-
- if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
- return true;
-
- SnapshotDirty->tid = tuple->t_ctid;
- return false; /* updated by other */
-}
-
-/*
- * HeapTupleSatisfiesSnapshot
- * True iff heap tuple is valid for the given snapshot.
- *
- * Here, we consider the effects of:
- * all transactions committed as of the time of the given snapshot
- * previous commands of this transaction
- *
- * Does _not_ include:
- * transactions shown as in-progress by the snapshot
- * transactions started after the snapshot was taken
- * changes made by the current command
- *
- * This is the same as HeapTupleSatisfiesNow, except that transactions that
- * were in progress or as yet unstarted when the snapshot was taken will
- * be treated as uncommitted, even if they have committed by now.
- *
- * (Notice, however, that the tuple status hint bits will be updated on the
- * basis of the true state of the transaction, even if we then pretend we
- * can't see it.)
- */
-bool
-HeapTupleSatisfiesSnapshot(HeapTupleHeader tuple, Snapshot snapshot)
-{
- /* XXX this is horribly ugly: */
- if (ReferentialIntegritySnapshotOverride)
- return HeapTupleSatisfiesNow(tuple);
-
- if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
- {
- if (tuple->t_infomask & HEAP_XMIN_INVALID)
- return false;
-
- if (tuple->t_infomask & HEAP_MOVED_OFF)
- {
- if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXvac(tuple)))
- return false;
- if (!TransactionIdIsInProgress(HeapTupleHeaderGetXvac(tuple)))
- {
- if (TransactionIdDidCommit(HeapTupleHeaderGetXvac(tuple)))
- {
- tuple->t_infomask |= HEAP_XMIN_INVALID;
- return false;
- }
- tuple->t_infomask |= HEAP_XMIN_COMMITTED;
- }
- }
- else if (tuple->t_infomask & HEAP_MOVED_IN)
- {
- if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXvac(tuple)))
- {
- if (TransactionIdIsInProgress(HeapTupleHeaderGetXvac(tuple)))
- return false;
- if (TransactionIdDidCommit(HeapTupleHeaderGetXvac(tuple)))
- tuple->t_infomask |= HEAP_XMIN_COMMITTED;
- else
- {
- tuple->t_infomask |= HEAP_XMIN_INVALID;
- return false;
- }
- }
- }
- else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
- {
- if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid)
- return false; /* inserted after scan started */
-
- if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
- return true;
-
- Assert(TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)));
-
- if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
- return true;
-
- if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
- return true; /* deleted after scan started */
- else
- return false; /* deleted before scan started */
- }
- else if (!TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
- {
- if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(tuple)))
- tuple->t_infomask |= HEAP_XMIN_INVALID;
- return false;
- }
- else
- tuple->t_infomask |= HEAP_XMIN_COMMITTED;
- }
-
- /*
- * By here, the inserting transaction has committed - have to check
- * when...
- */
- if (TransactionIdFollowsOrEquals(HeapTupleHeaderGetXmin(tuple),
- snapshot->xmin))
- {
- uint32 i;
-
- if (TransactionIdFollowsOrEquals(HeapTupleHeaderGetXmin(tuple),
- snapshot->xmax))
- return false;
-
- for (i = 0; i < snapshot->xcnt; i++)
- {
- if (TransactionIdEquals(HeapTupleHeaderGetXmin(tuple),
- snapshot->xip[i]))
- return false;
- }
- }
-
- if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
- return true;
-
- if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
- return true;
-
- if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
- {
- if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
- {
- if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
- return true; /* deleted after scan started */
- else
- return false; /* deleted before scan started */
- }
-
- if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
- {
- if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple)))
- tuple->t_infomask |= HEAP_XMAX_INVALID; /* aborted */
- return true;
- }
-
- /* xmax transaction committed */
- tuple->t_infomask |= HEAP_XMAX_COMMITTED;
- }
-
- /*
- * OK, the deleting transaction committed too ... but when?
- */
- if (TransactionIdFollowsOrEquals(HeapTupleHeaderGetXmax(tuple), snapshot->xmin))
- {
- uint32 i;
-
- if (TransactionIdFollowsOrEquals(HeapTupleHeaderGetXmax(tuple),
- snapshot->xmax))
- return true;
- for (i = 0; i < snapshot->xcnt; i++)
- {
- if (TransactionIdEquals(HeapTupleHeaderGetXmax(tuple), snapshot->xip[i]))
- return true;
- }
- }
-
- return false;
-}
-
-
-/*
- * HeapTupleSatisfiesVacuum
- *
- * Determine the status of tuples for VACUUM purposes. Here, what
- * we mainly want to know is if a tuple is potentially visible to *any*
- * running transaction. If so, it can't be removed yet by VACUUM.
- *
- * OldestXmin is a cutoff XID (obtained from GetOldestXmin()). Tuples
- * deleted by XIDs >= OldestXmin are deemed "recently dead"; they might
- * still be visible to some open transaction, so we can't remove them,
- * even if we see that the deleting transaction has committed.
- */
-HTSV_Result
-HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin)
-{
- /*
- * Has inserting transaction committed?
- *
- * If the inserting transaction aborted, then the tuple was never visible
- * to any other transaction, so we can delete it immediately.
- *
- * NOTE: must check TransactionIdIsInProgress (which looks in PROC array)
- * before TransactionIdDidCommit/TransactionIdDidAbort (which look in
- * pg_clog). Otherwise we have a race condition where we might decide
- * that a just-committed transaction crashed, because none of the
- * tests succeed. xact.c is careful to record commit/abort in pg_clog
- * before it unsets MyProc->xid in PROC array.
- */
- if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
- {
- if (tuple->t_infomask & HEAP_XMIN_INVALID)
- return HEAPTUPLE_DEAD;
- else if (tuple->t_infomask & HEAP_MOVED_OFF)
- {
- if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXvac(tuple)))
- return HEAPTUPLE_DELETE_IN_PROGRESS;
- if (TransactionIdIsInProgress(HeapTupleHeaderGetXvac(tuple)))
- return HEAPTUPLE_DELETE_IN_PROGRESS;
- if (TransactionIdDidCommit(HeapTupleHeaderGetXvac(tuple)))
- {
- 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(HeapTupleHeaderGetXvac(tuple)))
- return HEAPTUPLE_INSERT_IN_PROGRESS;
- if (TransactionIdIsInProgress(HeapTupleHeaderGetXvac(tuple)))
- return HEAPTUPLE_INSERT_IN_PROGRESS;
- if (TransactionIdDidCommit(HeapTupleHeaderGetXvac(tuple)))
- tuple->t_infomask |= HEAP_XMIN_COMMITTED;
- else
- {
- tuple->t_infomask |= HEAP_XMIN_INVALID;
- return HEAPTUPLE_DEAD;
- }
- }
- else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
- return HEAPTUPLE_INSERT_IN_PROGRESS;
- else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
- tuple->t_infomask |= HEAP_XMIN_COMMITTED;
- else if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(tuple)))
- {
- tuple->t_infomask |= HEAP_XMIN_INVALID;
- return HEAPTUPLE_DEAD;
- }
- else
- {
- /*
- * Not in Progress, Not Committed, Not Aborted - so it's from
- * crashed process. - vadim 11/26/96
- */
- tuple->t_infomask |= HEAP_XMIN_INVALID;
- return HEAPTUPLE_DEAD;
- }
- /* Should only get here if we set XMIN_COMMITTED */
- Assert(tuple->t_infomask & HEAP_XMIN_COMMITTED);
- }
-
- /*
- * Okay, the inserter committed, so it was good at some point. Now
- * what about the deleting transaction?
- */
- 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, so the tuple
- * is live in any case. However, we must make sure that either
- * XMAX_COMMITTED or XMAX_INVALID gets set once the xact is gone;
- * otherwise it is unsafe to recycle CLOG status after vacuuming.
- */
- if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
- {
- if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
- return HEAPTUPLE_LIVE;
- if (TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
- tuple->t_infomask |= HEAP_XMAX_COMMITTED;
- else /* it's either aborted or crashed */
- tuple->t_infomask |= HEAP_XMAX_INVALID;
- }
- return HEAPTUPLE_LIVE;
- }
-
- if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
- {
- if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
- return HEAPTUPLE_DELETE_IN_PROGRESS;
- else if (TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
- tuple->t_infomask |= HEAP_XMAX_COMMITTED;
- else if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple)))
- {
- tuple->t_infomask |= HEAP_XMAX_INVALID;
- return HEAPTUPLE_LIVE;
- }
- else
- {
- /*
- * Not in Progress, Not Committed, Not Aborted - so it's from
- * crashed process. - vadim 06/02/97
- */
- tuple->t_infomask |= HEAP_XMAX_INVALID;
- return HEAPTUPLE_LIVE;
- }
- /* Should only get here if we set XMAX_COMMITTED */
- Assert(tuple->t_infomask & HEAP_XMAX_COMMITTED);
- }
-
- /*
- * Deleter committed, but check special cases.
- */
-
- if (TransactionIdEquals(HeapTupleHeaderGetXmin(tuple),
- HeapTupleHeaderGetXmax(tuple)))
- {
- /*
- * inserter also deleted it, so it was never visible to anyone
- * else
- */
- return HEAPTUPLE_DEAD;
- }
-
- if (!TransactionIdPrecedes(HeapTupleHeaderGetXmax(tuple), OldestXmin))
- {
- /* deleting xact is too recent, tuple could still be visible */
- return HEAPTUPLE_RECENTLY_DEAD;
- }
-
- /* Otherwise, it's dead and removable */
- return HEAPTUPLE_DEAD;
-}
-
-
-/*
- * SetQuerySnapshot
- * Initialize query snapshot for a new query
- *
- * The SerializableSnapshot is the first one taken in a transaction.
- * In serializable mode we just use that one throughout the transaction.
- * In read-committed mode, we take a new snapshot at the start of each query.
- */
-void
-SetQuerySnapshot(void)
-{
- /* Initialize snapshot overriding to false */
- ReferentialIntegritySnapshotOverride = false;
-
- /* 1st call in xaction? */
- if (SerializableSnapshot == NULL)
- {
- SerializableSnapshot = GetSnapshotData(true);
- QuerySnapshot = SerializableSnapshot;
- Assert(QuerySnapshot != NULL);
- return;
- }
-
- if (QuerySnapshot != SerializableSnapshot)
- {
- free(QuerySnapshot->xip);
- free(QuerySnapshot);
- QuerySnapshot = NULL;
- }
-
- if (XactIsoLevel == XACT_SERIALIZABLE)
- QuerySnapshot = SerializableSnapshot;
- else
- QuerySnapshot = GetSnapshotData(false);
-
- Assert(QuerySnapshot != NULL);
-}
-
-/*
- * CopyQuerySnapshot
- * Copy the current query snapshot.
- *
- * Copying the snapshot is done so that a query is guaranteed to use a
- * consistent snapshot for its entire execution life, even if the command
- * counter is incremented or SetQuerySnapshot() is called while it runs
- * (as could easily happen, due to triggers etc. executing queries).
- *
- * The copy is palloc'd in the current memory context.
- */
-Snapshot
-CopyQuerySnapshot(void)
-{
- Snapshot snapshot;
-
- if (QuerySnapshot == NULL) /* should be set already, but... */
- SetQuerySnapshot();
-
- snapshot = (Snapshot) palloc(sizeof(SnapshotData));
- memcpy(snapshot, QuerySnapshot, sizeof(SnapshotData));
- if (snapshot->xcnt > 0)
- {
- snapshot->xip = (TransactionId *)
- palloc(snapshot->xcnt * sizeof(TransactionId));
- memcpy(snapshot->xip, QuerySnapshot->xip,
- snapshot->xcnt * sizeof(TransactionId));
- }
- else
- snapshot->xip = NULL;
-
- return snapshot;
-}
-
-/*
- * FreeXactSnapshot
- * Free snapshot(s) at end of transaction.
- */
-void
-FreeXactSnapshot(void)
-{
- if (QuerySnapshot != NULL && QuerySnapshot != SerializableSnapshot)
- {
- free(QuerySnapshot->xip);
- free(QuerySnapshot);
- }
-
- QuerySnapshot = NULL;
-
- if (SerializableSnapshot != NULL)
- {
- free(SerializableSnapshot->xip);
- free(SerializableSnapshot);
- }
-
- SerializableSnapshot = NULL;
-}