Re: invalid tid errors in latest 7.3.4 stable.

Поиск
Список
Период
Сортировка
От Tom Lane
Тема Re: invalid tid errors in latest 7.3.4 stable.
Дата
Msg-id 27660.1064516955@sss.pgh.pa.us
обсуждение исходный текст
Ответ на Re: invalid tid errors in latest 7.3.4 stable.  (Tom Lane <tgl@sss.pgh.pa.us>)
Ответы Re: invalid tid errors in latest 7.3.4 stable.  (Wade Klaver <archeron@wavefire.com>)
Re: invalid tid errors in latest 7.3.4 stable.  (Tom Lane <tgl@sss.pgh.pa.us>)
Список pgsql-hackers
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) \

В списке pgsql-hackers по дате отправления:

Предыдущее
От: Tom Lane
Дата:
Сообщение: Re: Question on adding new indexes to Postgresql
Следующее
От: "Keith Bottner"
Дата:
Сообщение: Re: Threads vs Processes (was: NuSphere and PostgreSQL for windows)