postgresql/src/backend/utils/time/tqual.c
Bruce Momjian 7971539020 heap_fetch requires buffer pointer, must be released; heap_getnext
no longer returns buffer pointer, can be gotten from scan;
	descriptor; bootstrap can create multi-key indexes;
pg_procname index now is multi-key index; oidint2, oidint4, oidname
are gone (must be removed from regression tests); use System Cache
rather than sequential scan in many places; heap_modifytuple no
longer takes buffer parameter; remove unused buffer parameter in
a few other functions; oid8 is not index-able; remove some use of
single-character variable names; cleanup Buffer variables usage
and scan descriptor looping; cleaned up allocation and freeing of
tuples; 18k lines of diff;
1998-08-19 02:04:17 +00:00

254 lines
7.2 KiB
C

/*-------------------------------------------------------------------------
*
* tqual.c--
* POSTGRES "time" qualification code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/time/tqual.c,v 1.17 1998/08/19 02:03:28 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/* #define TQUALDEBUG 1 */
#include "postgres.h"
#include "access/htup.h"
#include "access/xact.h"
#include "storage/bufmgr.h"
#include "access/transam.h"
#include "utils/elog.h"
#include "utils/palloc.h"
#include "utils/tqual.h"
extern bool PostgresIsInitialized;
/*
* XXX Transaction system override hacks start here
*/
#ifndef GOODAMI
TransactionId HeapSpecialTransactionId = InvalidTransactionId;
CommandId HeapSpecialCommandId = FirstCommandId;
void
setheapoverride(bool on)
{
if (on)
{
TransactionIdStore(GetCurrentTransactionId(),
&HeapSpecialTransactionId);
HeapSpecialCommandId = GetCurrentCommandId();
}
else
HeapSpecialTransactionId = InvalidTransactionId;
}
#endif /* !defined(GOODAMI) */
/*
* XXX Transaction system override hacks end here
*/
/*
* HeapTupleSatisfiesItself --
* True iff heap tuple is valid for "itself."
* "{it}self" means valid as of everything that's happened
* in the current transaction, _including_ the current command.
*
* Note:
* 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(HeapTuple tuple)
{
if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
{
if (tuple->t_infomask & HEAP_XMIN_INVALID) /* xid invalid or
* aborted */
return (false);
if (TransactionIdIsCurrentTransactionId(tuple->t_xmin))
{
if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
return (true);
else
return (false);
}
if (!TransactionIdDidCommit(tuple->t_xmin))
{
if (TransactionIdDidAbort(tuple->t_xmin))
tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */
return (false);
}
tuple->t_infomask |= HEAP_XMIN_COMMITTED;
}
/* the tuple was inserted validly */
if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
return (true);
if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
return (false);
if (TransactionIdIsCurrentTransactionId(tuple->t_xmax))
return (false);
if (!TransactionIdDidCommit(tuple->t_xmax))
{
if (TransactionIdDidAbort(tuple->t_xmax))
tuple->t_infomask |= HEAP_XMAX_INVALID; /* aborted */
return (true);
}
/* by here, deleting transaction has committed */
tuple->t_infomask |= HEAP_XMAX_COMMITTED;
return (false);
}
/*
* HeapTupleSatisfiesNow --
* True iff heap tuple is valid "now."
* "now" means valid including everything that's happened
* in the current transaction _up to, but not including,_
* the current command.
*
* 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
*
* XXX
* CommandId stuff didn't work properly if one used SQL-functions in
* UPDATE/INSERT(fromSELECT)/DELETE scans: SQL-funcs call
* CommandCounterIncrement and made tuples changed/inserted by
* current command visible to command itself (so we had multiple
* update of updated tuples, etc). - vadim 08/29/97
*
* 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(HeapTuple tuple)
{
if (AMI_OVERRIDE)
return true;
/*
* If the transaction system isn't yet initialized, then we assume
* that transactions committed. We only look at system catalogs
* during startup, so this is less awful than it seems, but it's still
* pretty awful.
*/
if (!PostgresIsInitialized)
return ((bool) (TransactionIdIsValid(tuple->t_xmin) &&
!TransactionIdIsValid(tuple->t_xmax)));
if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
{
if (tuple->t_infomask & HEAP_XMIN_INVALID) /* xid invalid or
* aborted */
return (false);
if (TransactionIdIsCurrentTransactionId(tuple->t_xmin))
{
if (CommandIdGEScanCommandId(tuple->t_cmin))
return (false); /* inserted after scan started */
if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
return (true);
Assert(TransactionIdIsCurrentTransactionId(tuple->t_xmax));
if (CommandIdGEScanCommandId(tuple->t_cmax))
return (true); /* deleted after scan started */
else
return (false); /* deleted before scan started */
}
/*
* this call is VERY expensive - requires a log table lookup.
*/
if (!TransactionIdDidCommit(tuple->t_xmin))
{
if (TransactionIdDidAbort(tuple->t_xmin))
tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */
return (false);
}
tuple->t_infomask |= HEAP_XMIN_COMMITTED;
}
/* 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)
return (false);
if (TransactionIdIsCurrentTransactionId(tuple->t_xmax))
{
if (CommandIdGEScanCommandId(tuple->t_cmax))
return (true); /* deleted after scan started */
else
return (false); /* deleted before scan started */
}
if (!TransactionIdDidCommit(tuple->t_xmax))
{
if (TransactionIdDidAbort(tuple->t_xmax))
tuple->t_infomask |= HEAP_XMAX_INVALID; /* aborted */
return (true);
}
/* xmax transaction committed */
tuple->t_infomask |= HEAP_XMAX_COMMITTED;
return (false);
}