I said:
> Okay, I'll work out some extension of the APIs to let us propagate the
> snapshot request down through SPI and into the Executor, rather than
> using a global variable for it. (Unless someone has a better idea...)
I've committed the attached patch into CVS HEAD. I am now wondering
whether to back-patch it to the 7.3 branch or not. It's a bit larger
than I would have liked, and really needs more testing before being
shoved into a stable branch.
The simplest test case I was able to generate for Wade's bug is this:
-----------
create table t1 (f1 int primary key);
create table t2 (f1 int references t1 on delete cascade);
create table t3 (f1 int);
create or replace function t2del() returns trigger as '
begin
update t3 set f1 = f1 + 1;
return old;
end' language plpgsql;
create trigger t2del before delete on t2 for each row
execute procedure t2del();
create or replace function t3upd() returns trigger as '
begin
perform count(*) from t3;
return new;
end' language plpgsql;
create trigger t3upd before update on t3 for each row
execute procedure t3upd();
insert into t1 values(1);
insert into t2 values(1);
insert into t3 values(1);
delete from t1;
-----------
Until this commit, CVS HEAD generated
ERROR: attempted to mark4update invisible tuple
CONTEXT: PL/pgSQL function "t2del" line 2 at SQL statement
7.3 branch generates a different spelling of the same error:
WARNING: Error occurred while executing PL/pgSQL function t2del
WARNING: line 2 at SQL statement
ERROR: heap_mark4update: (am)invalid tid
AFAICT you need a minimum of two levels of triggers invoked by an RI
trigger to make this happen, so it may be a corner case best left
unfixed in the 7.3 branch.
Opinions anyone?
regards, tom lane
*** src/backend/commands/explain.c.orig Mon Aug 11 16:46:46 2003
--- src/backend/commands/explain.c Thu Sep 25 12:51:27 2003
***************
*** 207,213 ****
gettimeofday(&starttime, NULL);
/* call ExecutorStart to prepare the plan for execution */
! ExecutorStart(queryDesc, !stmt->analyze);
/* Execute the plan for statistics if asked for */
if (stmt->analyze)
--- 207,213 ----
gettimeofday(&starttime, NULL);
/* call ExecutorStart to prepare the plan for execution */
! ExecutorStart(queryDesc, false, !stmt->analyze);
/* Execute the plan for statistics if asked for */
if (stmt->analyze)
*** src/backend/commands/trigger.c.orig Thu Sep 25 10:22:57 2003
--- src/backend/commands/trigger.c Thu Sep 25 12:51:27 2003
***************
*** 1863,1874 ****
heap_freetuple(rettuple);
/*
- * Might have been a referential integrity constraint trigger. Reset
- * the snapshot overriding flag.
- */
- ReferentialIntegritySnapshotOverride = false;
-
- /*
* Release buffers
*/
if (ItemPointerIsValid(&(event->dte_oldctid)))
--- 1863,1868 ----
*** src/backend/executor/execMain.c.orig Thu Sep 25 10:22:59 2003
--- src/backend/executor/execMain.c Thu Sep 25 14:00:34 2003
***************
*** 104,109 ****
--- 104,112 ----
* field of the QueryDesc is filled in to describe the tuples that will be
* returned, and the internal fields (estate and planstate) are set up.
*
+ * If useSnapshotNow is true, run the query with SnapshotNow time qual rules
+ * instead of the normal use of QuerySnapshot.
+ *
* If explainOnly is true, we are not actually intending to run the plan,
* only to set up for EXPLAIN; so skip unwanted side-effects.
*
***************
*** 112,118 ****
* ----------------------------------------------------------------
*/
void
! ExecutorStart(QueryDesc *queryDesc, bool explainOnly)
{
EState *estate;
MemoryContext oldcontext;
--- 115,121 ----
* ----------------------------------------------------------------
*/
void
! ExecutorStart(QueryDesc *queryDesc, bool useSnapshotNow, bool explainOnly)
{
EState *estate;
MemoryContext oldcontext;
***************
*** 154,160 ****
* the life of this query, even if it outlives the current command and
* current snapshot.
*/
! estate->es_snapshot = CopyQuerySnapshot();
/*
* Initialize the plan state tree
--- 157,172 ----
* the life of this query, even if it outlives the current command and
* current snapshot.
*/
! if (useSnapshotNow)
! {
! estate->es_snapshot = SnapshotNow;
! estate->es_snapshot_cid = GetCurrentCommandId();
! }
! else
! {
! estate->es_snapshot = CopyQuerySnapshot();
! estate->es_snapshot_cid = estate->es_snapshot->curcid;
! }
/*
* Initialize the plan state tree
***************
*** 1106,1112 ****
tuple.t_self = *((ItemPointer)
DatumGetPointer(datum));
test = heap_mark4update(erm->relation, &tuple,
&buffer,
!
estate->es_snapshot->curcid);
ReleaseBuffer(buffer);
switch (test)
{
--- 1118,1124 ----
tuple.t_self = *((ItemPointer)
DatumGetPointer(datum));
test = heap_mark4update(erm->relation, &tuple,
&buffer,
!
estate->es_snapshot_cid);
ReleaseBuffer(buffer);
switch (test)
{
***************
*** 1266,1272 ****
if (estate->es_into_relation_descriptor != NULL)
{
heap_insert(estate->es_into_relation_descriptor, tuple,
! estate->es_snapshot->curcid);
IncrAppended();
}
--- 1278,1284 ----
if (estate->es_into_relation_descriptor != NULL)
{
heap_insert(estate->es_into_relation_descriptor, tuple,
! estate->es_snapshot_cid);
IncrAppended();
}
***************
*** 1342,1348 ****
* insert the tuple
*/
newId = heap_insert(resultRelationDesc, tuple,
! estate->es_snapshot->curcid);
IncrAppended();
(estate->es_processed)++;
--- 1354,1360 ----
* insert the tuple
*/
newId = heap_insert(resultRelationDesc, tuple,
! estate->es_snapshot_cid);
IncrAppended();
(estate->es_processed)++;
***************
*** 1394,1400 ****
bool dodelete;
dodelete = ExecBRDeleteTriggers(estate, resultRelInfo, tupleid,
!
estate->es_snapshot->curcid);
if (!dodelete) /* "do nothing" */
return;
--- 1406,1412 ----
bool dodelete;
dodelete = ExecBRDeleteTriggers(estate, resultRelInfo, tupleid,
!
estate->es_snapshot_cid);
if (!dodelete) /* "do nothing" */
return;
***************
*** 1406,1412 ****
ldelete:;
result = heap_delete(resultRelationDesc, tupleid,
&ctid,
! estate->es_snapshot->curcid,
true /* wait for commit */);
switch (result)
{
--- 1418,1424 ----
ldelete:;
result = heap_delete(resultRelationDesc, tupleid,
&ctid,
! estate->es_snapshot_cid,
true /* wait for commit */);
switch (result)
{
***************
*** 1505,1511 ****
newtuple = ExecBRUpdateTriggers(estate, resultRelInfo,
tupleid, tuple,
!
estate->es_snapshot->curcid);
if (newtuple == NULL) /* "do nothing" */
return;
--- 1517,1523 ----
newtuple = ExecBRUpdateTriggers(estate, resultRelInfo,
tupleid, tuple,
!
estate->es_snapshot_cid);
if (newtuple == NULL) /* "do nothing" */
return;
***************
*** 1541,1547 ****
*/
result = heap_update(resultRelationDesc, tupleid, tuple,
&ctid,
! estate->es_snapshot->curcid,
true /* wait for commit */);
switch (result)
{
--- 1553,1559 ----
*/
result = heap_update(resultRelationDesc, tupleid, tuple,
&ctid,
! estate->es_snapshot_cid,
true /* wait for commit */);
switch (result)
{
***************
*** 2027,2032 ****
--- 2039,2045 ----
*/
epqstate->es_direction = ForwardScanDirection;
epqstate->es_snapshot = estate->es_snapshot;
+ epqstate->es_snapshot_cid = estate->es_snapshot_cid;
epqstate->es_range_table = estate->es_range_table;
epqstate->es_result_relations = estate->es_result_relations;
epqstate->es_num_result_relations = estate->es_num_result_relations;
*** src/backend/executor/execUtils.c.orig Wed Sep 24 14:54:01 2003
--- src/backend/executor/execUtils.c Thu Sep 25 14:00:35 2003
***************
*** 178,183 ****
--- 178,184 ----
*/
estate->es_direction = ForwardScanDirection;
estate->es_snapshot = SnapshotNow;
+ estate->es_snapshot_cid = FirstCommandId;
estate->es_range_table = NIL;
estate->es_result_relations = NULL;
*** src/backend/executor/functions.c.orig Thu Sep 25 10:22:59 2003
--- src/backend/executor/functions.c Thu Sep 25 12:51:10 2003
***************
*** 291,297 ****
/* Utility commands don't need Executor. */
if (es->qd->operation != CMD_UTILITY)
! ExecutorStart(es->qd, false);
es->status = F_EXEC_RUN;
}
--- 291,297 ----
/* Utility commands don't need Executor. */
if (es->qd->operation != CMD_UTILITY)
! ExecutorStart(es->qd, false, false);
es->status = F_EXEC_RUN;
}
*** src/backend/executor/nodeSubplan.c.orig Thu Sep 25 10:22:59 2003
--- src/backend/executor/nodeSubplan.c Thu Sep 25 14:00:35 2003
***************
*** 709,714 ****
--- 709,715 ----
sp_estate->es_tupleTable =
ExecCreateTupleTable(ExecCountSlotsNode(subplan->plan) + 10);
sp_estate->es_snapshot = estate->es_snapshot;
+ sp_estate->es_snapshot_cid = estate->es_snapshot_cid;
sp_estate->es_instrument = estate->es_instrument;
/*
*** src/backend/executor/nodeSubqueryscan.c.orig Sun Aug 3 23:00:35 2003
--- src/backend/executor/nodeSubqueryscan.c Thu Sep 25 14:00:35 2003
***************
*** 177,182 ****
--- 177,183 ----
sp_estate->es_tupleTable =
ExecCreateTupleTable(ExecCountSlotsNode(node->subplan) + 10);
sp_estate->es_snapshot = estate->es_snapshot;
+ sp_estate->es_snapshot_cid = estate->es_snapshot_cid;
sp_estate->es_instrument = estate->es_instrument;
/*
*** src/backend/executor/spi.c.orig Tue Sep 23 11:11:33 2003
--- src/backend/executor/spi.c Thu Sep 25 12:51:11 2003
***************
*** 32,41 ****
static int _SPI_curid = -1;
static int _SPI_execute(const char *src, int tcount, _SPI_plan *plan);
! static int _SPI_pquery(QueryDesc *queryDesc, bool runit, int tcount);
static int _SPI_execute_plan(_SPI_plan *plan,
! Datum *Values, const char *Nulls, int tcount);
static void _SPI_cursor_operation(Portal portal, bool forward, int count,
DestReceiver *dest);
--- 32,43 ----
static int _SPI_curid = -1;
static int _SPI_execute(const char *src, int tcount, _SPI_plan *plan);
! static int _SPI_pquery(QueryDesc *queryDesc, bool runit,
! bool useSnapshotNow, int tcount);
static int _SPI_execute_plan(_SPI_plan *plan,
! Datum *Values, const char
*Nulls,
! bool useSnapshotNow, int
tcount);
static void _SPI_cursor_operation(Portal portal, bool forward, int count,
DestReceiver *dest);
***************
*** 236,242 ****
if (res < 0)
return res;
! res = _SPI_execute_plan((_SPI_plan *) plan, Values, Nulls, tcount);
_SPI_end_call(true);
return res;
--- 238,270 ----
if (res < 0)
return res;
! res = _SPI_execute_plan((_SPI_plan *) plan, Values, Nulls, false, tcount);
!
! _SPI_end_call(true);
! return res;
! }
!
! /*
! * SPI_execp_now -- identical to SPI_execp, except that we use SnapshotNow
! * instead of the normal QuerySnapshot. This is currently not documented
! * in spi.sgml because it is only intended for use by RI triggers.
! */
! int
! SPI_execp_now(void *plan, Datum *Values, const char *Nulls, int tcount)
! {
! int res;
!
! if (plan == NULL || tcount < 0)
! return SPI_ERROR_ARGUMENT;
!
! if (((_SPI_plan *) plan)->nargs > 0 && Values == NULL)
! return SPI_ERROR_PARAM;
!
! res = _SPI_begin_call(true);
! if (res < 0)
! return res;
!
! res = _SPI_execute_plan((_SPI_plan *) plan, Values, Nulls, true, tcount);
_SPI_end_call(true);
return res;
***************
*** 1068,1074 ****
{
qdesc = CreateQueryDesc(queryTree, planTree, dest,
NULL,
false);
! res = _SPI_pquery(qdesc, true,
queryTree->canSetTag
? tcount : 0);
if (res < 0)
return res;
--- 1096,1102 ----
{
qdesc = CreateQueryDesc(queryTree, planTree, dest,
NULL,
false);
! res = _SPI_pquery(qdesc, true, false,
queryTree->canSetTag
? tcount : 0);
if (res < 0)
return res;
***************
*** 1078,1084 ****
{
qdesc = CreateQueryDesc(queryTree, planTree, dest,
NULL,
false);
! res = _SPI_pquery(qdesc, false, 0);
if (res < 0)
return res;
}
--- 1106,1112 ----
{
qdesc = CreateQueryDesc(queryTree, planTree, dest,
NULL,
false);
! res = _SPI_pquery(qdesc, false, false, 0);
if (res < 0)
return res;
}
***************
*** 1096,1102 ****
static int
_SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
! int tcount)
{
List *query_list_list = plan->qtlist;
List *plan_list = plan->ptlist;
--- 1124,1130 ----
static int
_SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
! bool useSnapshotNow, int tcount)
{
List *query_list_list = plan->qtlist;
List *plan_list = plan->ptlist;
***************
*** 1167,1173 ****
{
qdesc = CreateQueryDesc(queryTree, planTree, dest,
paramLI, false);
! res = _SPI_pquery(qdesc, true,
queryTree->canSetTag
? tcount : 0);
if (res < 0)
return res;
--- 1195,1201 ----
{
qdesc = CreateQueryDesc(queryTree, planTree, dest,
paramLI, false);
! res = _SPI_pquery(qdesc, true, useSnapshotNow,
queryTree->canSetTag
? tcount : 0);
if (res < 0)
return res;
***************
*** 1180,1186 ****
}
static int
! _SPI_pquery(QueryDesc *queryDesc, bool runit, int tcount)
{
int operation = queryDesc->operation;
int res;
--- 1208,1214 ----
}
static int
! _SPI_pquery(QueryDesc *queryDesc, bool runit, bool useSnapshotNow, int tcount)
{
int operation = queryDesc->operation;
int res;
***************
*** 1217,1223 ****
ResetUsage();
#endif
! ExecutorStart(queryDesc, false);
ExecutorRun(queryDesc, ForwardScanDirection, (long) tcount);
--- 1245,1251 ----
ResetUsage();
#endif
! ExecutorStart(queryDesc, useSnapshotNow, false);
ExecutorRun(queryDesc, ForwardScanDirection, (long) tcount);
*** src/backend/tcop/pquery.c.orig Tue Aug 12 14:23:21 2003
--- src/backend/tcop/pquery.c Thu Sep 25 12:50:59 2003
***************
*** 131,137 ****
/*
* Call ExecStart to prepare the plan for execution
*/
! ExecutorStart(queryDesc, false);
/*
* Run the plan to completion.
--- 131,137 ----
/*
* Call ExecStart to prepare the plan for execution
*/
! ExecutorStart(queryDesc, false, false);
/*
* Run the plan to completion.
***************
*** 269,275 ****
/*
* Call ExecStart to prepare the plan for execution
*/
! ExecutorStart(queryDesc, false);
/*
* This tells PortalCleanup to shut down the executor
--- 269,275 ----
/*
* Call ExecStart to prepare the plan for execution
*/
! ExecutorStart(queryDesc, false, false);
/*
* This tells PortalCleanup to shut down the executor
*** src/backend/utils/adt/ri_triggers.c.orig Thu Sep 25 10:23:14 2003
--- src/backend/utils/adt/ri_triggers.c Thu Sep 25 12:50:46 2003
***************
*** 187,194 ****
int i;
int match_type;
- ReferentialIntegritySnapshotOverride = true;
-
/*
* Check that this is a valid trigger call on the right time and
* event.
--- 187,192 ----
***************
*** 627,634 ****
int i;
int match_type;
- ReferentialIntegritySnapshotOverride = true;
-
/*
* Check that this is a valid trigger call on the right time and
* event.
--- 625,630 ----
***************
*** 807,814 ****
int i;
int match_type;
- ReferentialIntegritySnapshotOverride = true;
-
/*
* Check that this is a valid trigger call on the right time and
* event.
--- 803,808 ----
***************
*** 995,1002 ****
void *qplan;
int i;
- ReferentialIntegritySnapshotOverride = true;
-
/*
* Check that this is a valid trigger call on the right time and
* event.
--- 989,994 ----
***************
*** 1159,1166 ****
int i;
int j;
- ReferentialIntegritySnapshotOverride = true;
-
/*
* Check that this is a valid trigger call on the right time and
* event.
--- 1151,1156 ----
***************
*** 1349,1356 ****
void *qplan;
int i;
- ReferentialIntegritySnapshotOverride = true;
-
/*
* Check that this is a valid trigger call on the right time and
* event.
--- 1339,1344 ----
***************
*** 1520,1527 ****
void *qplan;
int i;
- ReferentialIntegritySnapshotOverride = true;
-
/*
* Check that this is a valid trigger call on the right time and
* event.
--- 1508,1513 ----
***************
*** 1694,1701 ****
void *qplan;
int i;
- ReferentialIntegritySnapshotOverride = true;
-
/*
* Check that this is a valid trigger call on the right time and
* event.
--- 1680,1685 ----
***************
*** 1868,1875 ****
int match_type;
bool use_cached_query;
- ReferentialIntegritySnapshotOverride = true;
-
/*
* Check that this is a valid trigger call on the right time and
* event.
--- 1852,1857 ----
***************
*** 2083,2090 ****
RI_QueryKey qkey;
void *qplan;
- ReferentialIntegritySnapshotOverride = true;
-
/*
* Check that this is a valid trigger call on the right time and
* event.
--- 2065,2070 ----
***************
*** 2296,2303 ****
void *qplan;
int match_type;
- ReferentialIntegritySnapshotOverride = true;
-
/*
* Check that this is a valid trigger call on the right time and
* event.
--- 2276,2281 ----
***************
*** 2936,2950 ****
*/
limit = (expect_OK == SPI_OK_SELECT) ? 1 : 0;
! /* Run the plan */
! spi_result = SPI_execp(qplan, vals, nulls, limit);
/* Restore UID */
SetUserId(save_uid);
/* Check result */
if (spi_result < 0)
! elog(ERROR, "SPI_execp failed");
if (expect_OK >= 0 && spi_result != expect_OK)
ri_ReportViolation(qkey, constrname ? constrname : "",
--- 2914,2932 ----
*/
limit = (expect_OK == SPI_OK_SELECT) ? 1 : 0;
! /*
! * Run the plan, using SnapshotNow time qual rules so that we can see
! * all committed tuples, even those committed after our own transaction
! * or query started.
! */
! spi_result = SPI_execp_now(qplan, vals, nulls, limit);
/* Restore UID */
SetUserId(save_uid);
/* Check result */
if (spi_result < 0)
! elog(ERROR, "SPI_execp_now returned %d", spi_result);
if (expect_OK >= 0 && spi_result != expect_OK)
ri_ReportViolation(qkey, constrname ? constrname : "",
*** src/backend/utils/time/tqual.c.orig Sun Sep 21 20:47:23 2003
--- src/backend/utils/time/tqual.c Thu Sep 25 12:50:38 2003
***************
*** 39,46 ****
TransactionId RecentXmin = InvalidTransactionId;
TransactionId RecentGlobalXmin = InvalidTransactionId;
- bool ReferentialIntegritySnapshotOverride = false;
-
/*
* HeapTupleSatisfiesItself
--- 39,44 ----
***************
*** 665,674 ****
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)
--- 663,668 ----
***************
*** 978,986 ****
void
SetQuerySnapshot(void)
{
- /* Initialize snapshot overriding to false */
- ReferentialIntegritySnapshotOverride = false;
-
/* 1st call in xaction? */
if (SerializableSnapshot == NULL)
{
--- 972,977 ----
*** src/include/access/valid.h.orig Sun Aug 3 23:01:27 2003
--- src/include/access/valid.h Thu Sep 25 12:50:32 2003
***************
*** 93,99 ****
relation, \
buffer, \
disk_page, \
! seeself, \
nKeys, \
key, \
res) \
--- 93,99 ----
relation, \
buffer, \
disk_page, \
! snapshot, \
nKeys, \
key, \
res) \
***************
*** 112,118 ****
{ \
uint16 _infomask = (tuple)->t_data->t_infomask; \
\
! (res) = HeapTupleSatisfiesVisibility((tuple), (seeself)); \
if ((tuple)->t_data->t_infomask != _infomask) \
SetBufferCommitInfoNeedsSave(buffer); \
} \
--- 112,118 ----
{ \
uint16 _infomask = (tuple)->t_data->t_infomask; \
\
! (res) = HeapTupleSatisfiesVisibility((tuple), (snapshot)); \
if ((tuple)->t_data->t_infomask != _infomask) \
SetBufferCommitInfoNeedsSave(buffer); \
} \
*** src/include/executor/executor.h.orig Mon Aug 18 21:13:41 2003
--- src/include/executor/executor.h Thu Sep 25 12:50:26 2003
***************
*** 85,91 ****
/*
* prototypes from functions in execMain.c
*/
! extern void ExecutorStart(QueryDesc *queryDesc, bool explainOnly);
extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction, long count);
extern void ExecutorEnd(QueryDesc *queryDesc);
--- 85,92 ----
/*
* prototypes from functions in execMain.c
*/
! extern void ExecutorStart(QueryDesc *queryDesc, bool useSnapshotNow,
! bool explainOnly);
extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction, long count);
extern void ExecutorEnd(QueryDesc *queryDesc);
*** src/include/executor/spi.h.orig Sun Aug 3 23:01:33 2003
--- src/include/executor/spi.h Thu Sep 25 12:50:26 2003
***************
*** 84,89 ****
--- 84,91 ----
extern int SPI_exec(const char *src, int tcount);
extern int SPI_execp(void *plan, Datum *values, const char *Nulls,
int tcount);
+ extern int SPI_execp_now(void *plan, Datum *values, const char *Nulls,
+ int tcount);
extern void *SPI_prepare(const char *src, int nargs, Oid *argtypes);
extern void *SPI_saveplan(void *plan);
extern int SPI_freeplan(void *plan);
*** src/include/nodes/execnodes.h.orig Fri Aug 22 16:30:27 2003
--- src/include/nodes/execnodes.h Thu Sep 25 13:52:34 2003
***************
*** 286,291 ****
--- 286,292 ----
/* Basic state for all query types: */
ScanDirection es_direction; /* current scan direction */
Snapshot es_snapshot; /* time qual to use */
+ CommandId es_snapshot_cid; /* CommandId component of time qual */
List *es_range_table; /* List of RangeTableEntrys */
/* Info about target table for insert/update/delete queries: */
*** src/include/utils/tqual.h.orig Sun Aug 3 23:01:45 2003
--- src/include/utils/tqual.h Thu Sep 25 12:50:12 2003
***************
*** 44,57 ****
extern TransactionId RecentXmin;
extern TransactionId RecentGlobalXmin;
- extern bool ReferentialIntegritySnapshotOverride;
-
- #define IsSnapshotNow(snapshot) ((Snapshot) (snapshot) == SnapshotNow)
- #define IsSnapshotSelf(snapshot) ((Snapshot) (snapshot) == SnapshotSelf)
- #define IsSnapshotAny(snapshot) ((Snapshot) (snapshot) == SnapshotAny)
- #define IsSnapshotToast(snapshot) ((Snapshot) (snapshot) == SnapshotToast)
- #define IsSnapshotDirty(snapshot) ((Snapshot) (snapshot) == SnapshotDirty)
-
/*
* HeapTupleSatisfiesVisibility
--- 44,49 ----
***************
*** 62,80 ****
* Beware of multiple evaluations of snapshot argument.
*/
#define HeapTupleSatisfiesVisibility(tuple, snapshot) \
! (IsSnapshotNow(snapshot) ? \
HeapTupleSatisfiesNow((tuple)->t_data) \
: \
! (IsSnapshotSelf(snapshot) ? \
HeapTupleSatisfiesItself((tuple)->t_data) \
: \
! (IsSnapshotAny(snapshot) ? \
true \
: \
! (IsSnapshotToast(snapshot) ? \
HeapTupleSatisfiesToast((tuple)->t_data) \
: \
! (IsSnapshotDirty(snapshot) ? \
HeapTupleSatisfiesDirty((tuple)->t_data) \
: \
HeapTupleSatisfiesSnapshot((tuple)->t_data,
snapshot) \
--- 54,72 ----
* Beware of multiple evaluations of snapshot argument.
*/
#define HeapTupleSatisfiesVisibility(tuple, snapshot) \
! ((snapshot) == SnapshotNow ? \
HeapTupleSatisfiesNow((tuple)->t_data) \
: \
! ((snapshot) == SnapshotSelf ? \
HeapTupleSatisfiesItself((tuple)->t_data) \
: \
! ((snapshot) == SnapshotAny ? \
true \
: \
! ((snapshot) == SnapshotToast ? \
HeapTupleSatisfiesToast((tuple)->t_data) \
: \
! ((snapshot) == SnapshotDirty ? \
HeapTupleSatisfiesDirty((tuple)->t_data) \
: \
HeapTupleSatisfiesSnapshot((tuple)->t_data,
snapshot) \
---------------------------(end of broadcast)---------------------------
TIP 3: if posting/reading through Usenet, please send an appropriate
subscribe-nomail command to [EMAIL PROTECTED] so that your
message can get through to the mailing list cleanly