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

Reply via email to