Re: "cancelling statement due to user request error" occurs but the transaction has committed.

Поиск
Список
Период
Сортировка
От Tom Lane
Тема Re: "cancelling statement due to user request error" occurs but the transaction has committed.
Дата
Msg-id 32348.1426812232@sss.pgh.pa.us
обсуждение исходный текст
Ответ на Re: "cancelling statement due to user request error" occurs but the transaction has committed.  (Bruce Momjian <bruce@momjian.us>)
Ответы Re: "cancelling statement due to user request error" occurs but the transaction has committed.  (Bruce Momjian <bruce@momjian.us>)
Список pgsql-hackers
Bruce Momjian <bruce@momjian.us> writes:
> On Thu, Mar 19, 2015 at 06:59:20PM -0300, Alvaro Herrera wrote:
>> I don't understand why aren't interrupts held until after the commit is
>> done -- including across the mentioned ereports.

> Uh, I think Robert was thinking of pre-commit triggers at the top of
> CommitTransaction() that might take a long time and we might want to
> cancel.

Yeah, that's a good point.  So really the only way to make this work as
requested is to have some cooperation between xact.c and postgres.c,
so that the hold taken midway through CommitTransaction is kept until
we reach the idle point.

The attached is only very lightly tested but shows what we probably
would need for this.  It's a bit messy in that the API for
CommitTransactionCommand leaves it unspecified whether interrupts are
held at exit; I'm not sure if it's useful or feasible to be more precise.

            regards, tom lane

diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 1495bb4..cedf5ee 100644
*** a/src/backend/access/transam/xact.c
--- b/src/backend/access/transam/xact.c
*************** static void CallSubXactCallbacks(SubXact
*** 274,280 ****
  static void CleanupTransaction(void);
  static void CheckTransactionChain(bool isTopLevel, bool throwError,
                        const char *stmtType);
! static void CommitTransaction(void);
  static TransactionId RecordTransactionAbort(bool isSubXact);
  static void StartTransaction(void);

--- 274,280 ----
  static void CleanupTransaction(void);
  static void CheckTransactionChain(bool isTopLevel, bool throwError,
                        const char *stmtType);
! static void CommitTransaction(bool keep_holdoff);
  static TransactionId RecordTransactionAbort(bool isSubXact);
  static void StartTransaction(void);

*************** StartTransaction(void)
*** 1762,1771 ****
  /*
   *    CommitTransaction
   *
   * NB: if you change this routine, better look at PrepareTransaction too!
   */
  static void
! CommitTransaction(void)
  {
      TransactionState s = CurrentTransactionState;
      TransactionId latestXid;
--- 1762,1775 ----
  /*
   *    CommitTransaction
   *
+  * If keep_holdoff is true, we return with interrupts still held off;
+  * this is appropriate if caller has something to do that should be
+  * considered part of post-commit cleanup.
+  *
   * NB: if you change this routine, better look at PrepareTransaction too!
   */
  static void
! CommitTransaction(bool keep_holdoff)
  {
      TransactionState s = CurrentTransactionState;
      TransactionId latestXid;
*************** CommitTransaction(void)
*** 1837,1843 ****
       */
      PreCommit_Notify();

!     /* Prevent cancel/die interrupt while cleaning up */
      HOLD_INTERRUPTS();

      /* Commit updates to the relation map --- do this as late as possible */
--- 1841,1851 ----
       */
      PreCommit_Notify();

!     /*
!      * Prevent cancel/die interrupt while cleaning up.  If caller passes
!      * keep_holdoff = true, interrupts will remain held till caller resumes
!      * them.
!      */
      HOLD_INTERRUPTS();

      /* Commit updates to the relation map --- do this as late as possible */
*************** CommitTransaction(void)
*** 1958,1974 ****
       */
      s->state = TRANS_DEFAULT;

!     RESUME_INTERRUPTS();
  }


  /*
   *    PrepareTransaction
   *
   * NB: if you change this routine, better look at CommitTransaction too!
   */
  static void
! PrepareTransaction(void)
  {
      TransactionState s = CurrentTransactionState;
      TransactionId xid = GetCurrentTransactionId();
--- 1966,1987 ----
       */
      s->state = TRANS_DEFAULT;

!     if (!keep_holdoff)
!         RESUME_INTERRUPTS();
  }


  /*
   *    PrepareTransaction
   *
+  * If keep_holdoff is true, we return with interrupts still held off;
+  * this is appropriate if caller has something to do that should be
+  * considered part of post-commit cleanup.
+  *
   * NB: if you change this routine, better look at CommitTransaction too!
   */
  static void
! PrepareTransaction(bool keep_holdoff)
  {
      TransactionState s = CurrentTransactionState;
      TransactionId xid = GetCurrentTransactionId();
*************** PrepareTransaction(void)
*** 2067,2073 ****
                  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
          errmsg("cannot PREPARE a transaction that has exported snapshots")));

!     /* Prevent cancel/die interrupt while cleaning up */
      HOLD_INTERRUPTS();

      /*
--- 2080,2090 ----
                  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
          errmsg("cannot PREPARE a transaction that has exported snapshots")));

!     /*
!      * Prevent cancel/die interrupt while cleaning up.  If caller passes
!      * keep_holdoff = true, interrupts will remain held till caller resumes
!      * them.
!      */
      HOLD_INTERRUPTS();

      /*
*************** PrepareTransaction(void)
*** 2225,2231 ****
       */
      s->state = TRANS_DEFAULT;

!     RESUME_INTERRUPTS();
  }


--- 2242,2249 ----
       */
      s->state = TRANS_DEFAULT;

!     if (!keep_holdoff)
!         RESUME_INTERRUPTS();
  }


*************** StartTransactionCommand(void)
*** 2492,2500 ****

  /*
   *    CommitTransactionCommand
   */
  void
! CommitTransactionCommand(void)
  {
      TransactionState s = CurrentTransactionState;

--- 2510,2524 ----

  /*
   *    CommitTransactionCommand
+  *
+  * If keep_holdoff is true, and we perform a transaction commit or prepare,
+  * we return with interrupts still held off; this is appropriate if caller has
+  * something to do that should be considered part of post-commit cleanup.
+  * Note that callers passing "true" must be prepared for either the case that
+  * interrupts are held or that they're not.
   */
  void
! CommitTransactionCommand(bool keep_holdoff)
  {
      TransactionState s = CurrentTransactionState;

*************** CommitTransactionCommand(void)
*** 2515,2521 ****
               * transaction commit, and return to the idle state.
               */
          case TBLOCK_STARTED:
!             CommitTransaction();
              s->blockState = TBLOCK_DEFAULT;
              break;

--- 2539,2545 ----
               * transaction commit, and return to the idle state.
               */
          case TBLOCK_STARTED:
!             CommitTransaction(keep_holdoff);
              s->blockState = TBLOCK_DEFAULT;
              break;

*************** CommitTransactionCommand(void)
*** 2544,2550 ****
               * idle state.
               */
          case TBLOCK_END:
!             CommitTransaction();
              s->blockState = TBLOCK_DEFAULT;
              break;

--- 2568,2574 ----
               * idle state.
               */
          case TBLOCK_END:
!             CommitTransaction(keep_holdoff);
              s->blockState = TBLOCK_DEFAULT;
              break;

*************** CommitTransactionCommand(void)
*** 2583,2589 ****
               * return to the idle state.
               */
          case TBLOCK_PREPARE:
!             PrepareTransaction();
              s->blockState = TBLOCK_DEFAULT;
              break;

--- 2607,2613 ----
               * return to the idle state.
               */
          case TBLOCK_PREPARE:
!             PrepareTransaction(keep_holdoff);
              s->blockState = TBLOCK_DEFAULT;
              break;

*************** CommitTransactionCommand(void)
*** 2634,2646 ****
              if (s->blockState == TBLOCK_END)
              {
                  Assert(s->parent == NULL);
!                 CommitTransaction();
                  s->blockState = TBLOCK_DEFAULT;
              }
              else if (s->blockState == TBLOCK_PREPARE)
              {
                  Assert(s->parent == NULL);
!                 PrepareTransaction();
                  s->blockState = TBLOCK_DEFAULT;
              }
              else
--- 2658,2670 ----
              if (s->blockState == TBLOCK_END)
              {
                  Assert(s->parent == NULL);
!                 CommitTransaction(keep_holdoff);
                  s->blockState = TBLOCK_DEFAULT;
              }
              else if (s->blockState == TBLOCK_PREPARE)
              {
                  Assert(s->parent == NULL);
!                 PrepareTransaction(keep_holdoff);
                  s->blockState = TBLOCK_DEFAULT;
              }
              else
*************** CommitTransactionCommand(void)
*** 2655,2661 ****
               */
          case TBLOCK_SUBABORT_END:
              CleanupSubTransaction();
!             CommitTransactionCommand();
              break;

              /*
--- 2679,2685 ----
               */
          case TBLOCK_SUBABORT_END:
              CleanupSubTransaction();
!             CommitTransactionCommand(keep_holdoff);
              break;

              /*
*************** CommitTransactionCommand(void)
*** 2664,2670 ****
          case TBLOCK_SUBABORT_PENDING:
              AbortSubTransaction();
              CleanupSubTransaction();
!             CommitTransactionCommand();
              break;

              /*
--- 2688,2694 ----
          case TBLOCK_SUBABORT_PENDING:
              AbortSubTransaction();
              CleanupSubTransaction();
!             CommitTransactionCommand(keep_holdoff);
              break;

              /*
*************** BeginInternalSubTransaction(char *name)
*** 3779,3785 ****
              break;
      }

!     CommitTransactionCommand();
      StartTransactionCommand();
  }

--- 3803,3809 ----
              break;
      }

!     CommitTransactionCommand(false);
      StartTransactionCommand();
  }

diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index 6e563b6..cb14f08 100644
*** a/src/backend/bootstrap/bootparse.y
--- b/src/backend/bootstrap/bootparse.y
*************** do_start(void)
*** 77,83 ****
  static void
  do_end(void)
  {
!     CommitTransactionCommand();
      elog(DEBUG4, "commit transaction");
      CHECK_FOR_INTERRUPTS();        /* allow SIGINT to kill bootstrap run */
      if (isatty(0))
--- 77,83 ----
  static void
  do_end(void)
  {
!     CommitTransactionCommand(false);
      elog(DEBUG4, "commit transaction");
      CHECK_FOR_INTERRUPTS();        /* allow SIGINT to kill bootstrap run */
      if (isatty(0))
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index f85ed93..0bef8ad 100644
*** a/src/backend/catalog/index.c
--- b/src/backend/catalog/index.c
*************** index_drop(Oid indexId, bool concurrent)
*** 1453,1459 ****
          LockRelationIdForSession(&indexrelid, ShareUpdateExclusiveLock);

          PopActiveSnapshot();
!         CommitTransactionCommand();
          StartTransactionCommand();

          /*
--- 1453,1459 ----
          LockRelationIdForSession(&indexrelid, ShareUpdateExclusiveLock);

          PopActiveSnapshot();
!         CommitTransactionCommand(false);
          StartTransactionCommand();

          /*
*************** index_drop(Oid indexId, bool concurrent)
*** 1507,1513 ****
           * Again, commit the transaction to make the pg_index update visible
           * to other sessions.
           */
!         CommitTransactionCommand();
          StartTransactionCommand();

          /*
--- 1507,1513 ----
           * Again, commit the transaction to make the pg_index update visible
           * to other sessions.
           */
!         CommitTransactionCommand(false);
          StartTransactionCommand();

          /*
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 1af977c..460c1fd 100644
*** a/src/backend/catalog/namespace.c
--- b/src/backend/catalog/namespace.c
*************** RemoveTempRelationsCallback(int code, Da
*** 3855,3861 ****

          RemoveTempRelations(myTempNamespace);

!         CommitTransactionCommand();
      }
  }

--- 3855,3861 ----

          RemoveTempRelations(myTempNamespace);

!         CommitTransactionCommand(false);
      }
  }

diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 2826b7e..1bee7a6 100644
*** a/src/backend/commands/async.c
--- b/src/backend/commands/async.c
*************** ProcessCompletedNotifies(void)
*** 1104,1110 ****
          asyncQueueAdvanceTail();
      }

!     CommitTransactionCommand();

      MemoryContextSwitchTo(caller_context);

--- 1104,1110 ----
          asyncQueueAdvanceTail();
      }

!     CommitTransactionCommand(false);

      MemoryContextSwitchTo(caller_context);

*************** ProcessIncomingNotify(void)
*** 1988,1994 ****

      asyncQueueReadAllNotifications();

!     CommitTransactionCommand();

      /*
       * Must flush the notify messages to ensure frontend gets them promptly.
--- 1988,1994 ----

      asyncQueueReadAllNotifications();

!     CommitTransactionCommand(false);

      /*
       * Must flush the notify messages to ensure frontend gets them promptly.
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 3febdd5..1c5d476 100644
*** a/src/backend/commands/cluster.c
--- b/src/backend/commands/cluster.c
*************** cluster(ClusterStmt *stmt, bool isTopLev
*** 214,220 ****

          /* Commit to get out of starting transaction */
          PopActiveSnapshot();
!         CommitTransactionCommand();

          /* Ok, now that we've got them all, cluster them one by one */
          foreach(rv, rvs)
--- 214,220 ----

          /* Commit to get out of starting transaction */
          PopActiveSnapshot();
!         CommitTransactionCommand(false);

          /* Ok, now that we've got them all, cluster them one by one */
          foreach(rv, rvs)
*************** cluster(ClusterStmt *stmt, bool isTopLev
*** 228,234 ****
              /* Do the job. */
              cluster_rel(rvtc->tableOid, rvtc->indexOid, true, stmt->verbose);
              PopActiveSnapshot();
!             CommitTransactionCommand();
          }

          /* Start a new transaction for the cleanup work. */
--- 228,234 ----
              /* Do the job. */
              cluster_rel(rvtc->tableOid, rvtc->indexOid, true, stmt->verbose);
              PopActiveSnapshot();
!             CommitTransactionCommand(false);
          }

          /* Start a new transaction for the cleanup work. */
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index a699ce3..8f7a51f 100644
*** a/src/backend/commands/dbcommands.c
--- b/src/backend/commands/dbcommands.c
*************** movedb(const char *dbname, const char *t
*** 1312,1318 ****
       * really commits.
       */
      PopActiveSnapshot();
!     CommitTransactionCommand();

      /* Start new transaction for the remaining work; don't need a snapshot */
      StartTransactionCommand();
--- 1312,1318 ----
       * really commits.
       */
      PopActiveSnapshot();
!     CommitTransactionCommand(false);

      /* Start new transaction for the remaining work; don't need a snapshot */
      StartTransactionCommand();
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 1c1d0da..b76738c 100644
*** a/src/backend/commands/indexcmds.c
--- b/src/backend/commands/indexcmds.c
*************** DefineIndex(Oid relationId,
*** 663,669 ****
      LockRelationIdForSession(&heaprelid, ShareUpdateExclusiveLock);

      PopActiveSnapshot();
!     CommitTransactionCommand();
      StartTransactionCommand();

      /*
--- 663,669 ----
      LockRelationIdForSession(&heaprelid, ShareUpdateExclusiveLock);

      PopActiveSnapshot();
!     CommitTransactionCommand(false);
      StartTransactionCommand();

      /*
*************** DefineIndex(Oid relationId,
*** 737,743 ****
      /*
       * Commit this transaction to make the indisready update visible.
       */
!     CommitTransactionCommand();
      StartTransactionCommand();

      /*
--- 737,743 ----
      /*
       * Commit this transaction to make the indisready update visible.
       */
!     CommitTransactionCommand(false);
      StartTransactionCommand();

      /*
*************** ReindexMultipleTables(const char *object
*** 1914,1920 ****

      /* Now reindex each rel in a separate transaction */
      PopActiveSnapshot();
!     CommitTransactionCommand();
      foreach(l, relids)
      {
          Oid            relid = lfirst_oid(l);
--- 1914,1920 ----

      /* Now reindex each rel in a separate transaction */
      PopActiveSnapshot();
!     CommitTransactionCommand(false);
      foreach(l, relids)
      {
          Oid            relid = lfirst_oid(l);
*************** ReindexMultipleTables(const char *object
*** 1930,1936 ****
                              get_namespace_name(get_rel_namespace(relid)),
                              get_rel_name(relid))));
          PopActiveSnapshot();
!         CommitTransactionCommand();
      }
      StartTransactionCommand();

--- 1930,1936 ----
                              get_namespace_name(get_rel_namespace(relid)),
                              get_rel_name(relid))));
          PopActiveSnapshot();
!         CommitTransactionCommand(false);
      }
      StartTransactionCommand();

diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index bd57b68..c69610d 100644
*** a/src/backend/commands/vacuum.c
--- b/src/backend/commands/vacuum.c
*************** vacuum(int options, RangeVar *relation,
*** 263,269 ****
              PopActiveSnapshot();

          /* matches the StartTransaction in PostgresMain() */
!         CommitTransactionCommand();
      }

      /* Turn vacuum cost accounting on or off */
--- 263,269 ----
              PopActiveSnapshot();

          /* matches the StartTransaction in PostgresMain() */
!         CommitTransactionCommand(false);
      }

      /* Turn vacuum cost accounting on or off */
*************** vacuum(int options, RangeVar *relation,
*** 310,316 ****
                  if (use_own_xacts)
                  {
                      PopActiveSnapshot();
!                     CommitTransactionCommand();
                  }
              }
          }
--- 310,316 ----
                  if (use_own_xacts)
                  {
                      PopActiveSnapshot();
!                     CommitTransactionCommand(false);
                  }
              }
          }
*************** vacuum_rel(Oid relid, RangeVar *relation
*** 1243,1249 ****
      if (!onerel)
      {
          PopActiveSnapshot();
!         CommitTransactionCommand();
          return false;
      }

--- 1243,1249 ----
      if (!onerel)
      {
          PopActiveSnapshot();
!         CommitTransactionCommand(false);
          return false;
      }

*************** vacuum_rel(Oid relid, RangeVar *relation
*** 1274,1280 ****
                              RelationGetRelationName(onerel))));
          relation_close(onerel, lmode);
          PopActiveSnapshot();
!         CommitTransactionCommand();
          return false;
      }

--- 1274,1280 ----
                              RelationGetRelationName(onerel))));
          relation_close(onerel, lmode);
          PopActiveSnapshot();
!         CommitTransactionCommand(false);
          return false;
      }

*************** vacuum_rel(Oid relid, RangeVar *relation
*** 1292,1298 ****
                          RelationGetRelationName(onerel))));
          relation_close(onerel, lmode);
          PopActiveSnapshot();
!         CommitTransactionCommand();
          return false;
      }

--- 1292,1298 ----
                          RelationGetRelationName(onerel))));
          relation_close(onerel, lmode);
          PopActiveSnapshot();
!         CommitTransactionCommand(false);
          return false;
      }

*************** vacuum_rel(Oid relid, RangeVar *relation
*** 1307,1313 ****
      {
          relation_close(onerel, lmode);
          PopActiveSnapshot();
!         CommitTransactionCommand();
          return false;
      }

--- 1307,1313 ----
      {
          relation_close(onerel, lmode);
          PopActiveSnapshot();
!         CommitTransactionCommand(false);
          return false;
      }

*************** vacuum_rel(Oid relid, RangeVar *relation
*** 1375,1381 ****
       * Complete the transaction and free all temporary memory used.
       */
      PopActiveSnapshot();
!     CommitTransactionCommand();

      /*
       * If the relation has a secondary toast rel, vacuum that too while we
--- 1375,1381 ----
       * Complete the transaction and free all temporary memory used.
       */
      PopActiveSnapshot();
!     CommitTransactionCommand(false);

      /*
       * If the relation has a secondary toast rel, vacuum that too while we
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 5ccae24..b593437 100644
*** a/src/backend/postmaster/autovacuum.c
--- b/src/backend/postmaster/autovacuum.c
*************** get_database_list(void)
*** 1847,1853 ****
      heap_endscan(scan);
      heap_close(rel, AccessShareLock);

!     CommitTransactionCommand();

      return dblist;
  }
--- 1847,1853 ----
      heap_endscan(scan);
      heap_close(rel, AccessShareLock);

!     CommitTransactionCommand(false);

      return dblist;
  }
*************** deleted:
*** 2355,2361 ****
      vac_update_datfrozenxid();

      /* Finally close out the last transaction. */
!     CommitTransactionCommand();
  }

  /*
--- 2355,2361 ----
      vac_update_datfrozenxid();

      /* Finally close out the last transaction. */
!     CommitTransactionCommand(false);
  }

  /*
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 2956119..833fd69 100644
*** a/src/backend/replication/walsender.c
--- b/src/backend/replication/walsender.c
*************** IdentifySystem(void)
*** 331,337 ****
          /* make dbname live outside TX context */
          MemoryContextSwitchTo(cur);
          dbname = get_database_name(MyDatabaseId);
!         CommitTransactionCommand();
          /* CommitTransactionCommand switches to TopMemoryContext */
          MemoryContextSwitchTo(cur);
      }
--- 331,337 ----
          /* make dbname live outside TX context */
          MemoryContextSwitchTo(cur);
          dbname = get_database_name(MyDatabaseId);
!         CommitTransactionCommand(false);
          /* CommitTransactionCommand switches to TopMemoryContext */
          MemoryContextSwitchTo(cur);
      }
diff --git a/src/backend/storage/ipc/sinval.c b/src/backend/storage/ipc/sinval.c
index 67ec515..ed3961e 100644
*** a/src/backend/storage/ipc/sinval.c
--- b/src/backend/storage/ipc/sinval.c
*************** ProcessCatchupInterrupt(void)
*** 200,206 ****
          {
              elog(DEBUG4, "ProcessCatchupEvent outside transaction");
              StartTransactionCommand();
!             CommitTransactionCommand();
          }
      }
  }
--- 200,206 ----
          {
              elog(DEBUG4, "ProcessCatchupEvent outside transaction");
              StartTransactionCommand();
!             CommitTransactionCommand(false);
          }
      }
  }
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 33720e8..ab361cd 100644
*** a/src/backend/tcop/postgres.c
--- b/src/backend/tcop/postgres.c
*************** static int    errdetail_params(ParamListInf
*** 190,196 ****
  static int    errdetail_abort(void);
  static int    errdetail_recovery_conflict(void);
  static void start_xact_command(void);
! static void finish_xact_command(void);
  static bool IsTransactionExitStmt(Node *parsetree);
  static bool IsTransactionExitStmtList(List *parseTrees);
  static bool IsTransactionStmtList(List *parseTrees);
--- 190,196 ----
  static int    errdetail_abort(void);
  static int    errdetail_recovery_conflict(void);
  static void start_xact_command(void);
! static void finish_xact_command(bool keep_holdoff);
  static bool IsTransactionExitStmt(Node *parsetree);
  static bool IsTransactionExitStmtList(List *parseTrees);
  static bool IsTransactionStmtList(List *parseTrees);
*************** exec_simple_query(const char *query_stri
*** 1111,1125 ****

          PortalDrop(portal, false);

!         if (IsA(parsetree, TransactionStmt))
!         {
!             /*
!              * If this was a transaction control statement, commit it. We will
!              * start a new xact command for the next command (if any).
!              */
!             finish_xact_command();
!         }
!         else if (lnext(parsetree_item) == NULL)
          {
              /*
               * If this is the last parsetree of the query string, close down
--- 1111,1117 ----

          PortalDrop(portal, false);

!         if (lnext(parsetree_item) == NULL)
          {
              /*
               * If this is the last parsetree of the query string, close down
*************** exec_simple_query(const char *query_stri
*** 1131,1137 ****
               * historical Postgres behavior, we do not force a transaction
               * boundary between queries appearing in a single query string.
               */
!             finish_xact_command();
          }
          else
          {
--- 1123,1138 ----
               * historical Postgres behavior, we do not force a transaction
               * boundary between queries appearing in a single query string.
               */
!             finish_xact_command(true);
!         }
!         else if (IsA(parsetree, TransactionStmt))
!         {
!             /*
!              * If this was a transaction control statement, commit it. We will
!              * start a new xact command for the next command.  We know there
!              * is another one, so don't hold off interrupts.
!              */
!             finish_xact_command(false);
          }
          else
          {
*************** exec_simple_query(const char *query_stri
*** 1154,1160 ****
      /*
       * Close down transaction statement, if one is open.
       */
!     finish_xact_command();

      /*
       * If there were no parsetrees, return EmptyQueryResponse message.
--- 1155,1161 ----
      /*
       * Close down transaction statement, if one is open.
       */
!     finish_xact_command(true);

      /*
       * If there were no parsetrees, return EmptyQueryResponse message.
*************** exec_execute_message(const char *portal_
*** 2001,2007 ****
               * If this was a transaction control statement, commit it.  We
               * will start a new xact command for the next command (if any).
               */
!             finish_xact_command();
          }
          else
          {
--- 2002,2008 ----
               * If this was a transaction control statement, commit it.  We
               * will start a new xact command for the next command (if any).
               */
!             finish_xact_command(true);
          }
          else
          {
*************** start_xact_command(void)
*** 2453,2459 ****
  }

  static void
! finish_xact_command(void)
  {
      if (xact_started)
      {
--- 2454,2460 ----
  }

  static void
! finish_xact_command(bool keep_holdoff)
  {
      if (xact_started)
      {
*************** finish_xact_command(void)
*** 2464,2470 ****
          ereport(DEBUG3,
                  (errmsg_internal("CommitTransactionCommand")));

!         CommitTransactionCommand();

  #ifdef MEMORY_CONTEXT_CHECKING
          /* Check all memory contexts that weren't freed during commit */
--- 2465,2471 ----
          ereport(DEBUG3,
                  (errmsg_internal("CommitTransactionCommand")));

!         CommitTransactionCommand(keep_holdoff);

  #ifdef MEMORY_CONTEXT_CHECKING
          /* Check all memory contexts that weren't freed during commit */
*************** PostgresMain(int argc, char *argv[],
*** 3964,3969 ****
--- 3965,3976 ----
          }

          /*
+          * Resume interrupts, in case they were held off thanks to a COMMIT.
+          */
+         InterruptHoldoffCount = 0;
+         CHECK_FOR_INTERRUPTS();
+
+         /*
           * (2) Allow asynchronous signals to be executed immediately if they
           * come in while we are waiting for client input. (This must be
           * conditional since we don't want, say, reads on behalf of COPY FROM
*************** PostgresMain(int argc, char *argv[],
*** 4127,4133 ****
                  }

                  /* commit the function-invocation transaction */
!                 finish_xact_command();

                  send_ready_for_query = true;
                  break;
--- 4134,4140 ----
                  }

                  /* commit the function-invocation transaction */
!                 finish_xact_command(true);

                  send_ready_for_query = true;
                  break;
*************** PostgresMain(int argc, char *argv[],
*** 4216,4222 ****

              case 'S':            /* sync */
                  pq_getmsgend(&input_message);
!                 finish_xact_command();
                  send_ready_for_query = true;
                  break;

--- 4223,4229 ----

              case 'S':            /* sync */
                  pq_getmsgend(&input_message);
!                 finish_xact_command(true);
                  send_ready_for_query = true;
                  break;

diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 1e646a1..59eb697 100644
*** a/src/backend/utils/init/postinit.c
--- b/src/backend/utils/init/postinit.c
*************** InitPostgres(const char *in_dbname, Oid
*** 794,800 ****
          pgstat_bestart();

          /* close the transaction we started above */
!         CommitTransactionCommand();

          return;
      }
--- 794,800 ----
          pgstat_bestart();

          /* close the transaction we started above */
!         CommitTransactionCommand(false);

          return;
      }
*************** InitPostgres(const char *in_dbname, Oid
*** 973,979 ****

      /* close the transaction we started above */
      if (!bootstrap)
!         CommitTransactionCommand();
  }

  /*
--- 973,979 ----

      /* close the transaction we started above */
      if (!bootstrap)
!         CommitTransactionCommand(false);
  }

  /*
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index fdf3ea3..59e5df0 100644
*** a/src/include/access/xact.h
--- b/src/include/access/xact.h
*************** extern bool TransactionIdIsCurrentTransa
*** 308,314 ****
  extern void CommandCounterIncrement(void);
  extern void ForceSyncCommit(void);
  extern void StartTransactionCommand(void);
! extern void CommitTransactionCommand(void);
  extern void AbortCurrentTransaction(void);
  extern void BeginTransactionBlock(void);
  extern bool EndTransactionBlock(void);
--- 308,314 ----
  extern void CommandCounterIncrement(void);
  extern void ForceSyncCommit(void);
  extern void StartTransactionCommand(void);
! extern void CommitTransactionCommand(bool keep_holdoff);
  extern void AbortCurrentTransaction(void);
  extern void BeginTransactionBlock(void);
  extern bool EndTransactionBlock(void);
diff --git a/src/test/modules/worker_spi/worker_spi.c b/src/test/modules/worker_spi/worker_spi.c
index 4149c94..c8882ff 100644
*** a/src/test/modules/worker_spi/worker_spi.c
--- b/src/test/modules/worker_spi/worker_spi.c
*************** initialize_worker_spi(worktable *table)
*** 154,160 ****

      SPI_finish();
      PopActiveSnapshot();
!     CommitTransactionCommand();
      pgstat_report_activity(STATE_IDLE, NULL);
  }

--- 154,160 ----

      SPI_finish();
      PopActiveSnapshot();
!     CommitTransactionCommand(false);
      pgstat_report_activity(STATE_IDLE, NULL);
  }

*************** worker_spi_main(Datum main_arg)
*** 291,297 ****
           */
          SPI_finish();
          PopActiveSnapshot();
!         CommitTransactionCommand();
          pgstat_report_activity(STATE_IDLE, NULL);
      }

--- 291,297 ----
           */
          SPI_finish();
          PopActiveSnapshot();
!         CommitTransactionCommand(false);
          pgstat_report_activity(STATE_IDLE, NULL);
      }


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

Предыдущее
От: Bruce Momjian
Дата:
Сообщение: Re: proposal: doc: simplify examples of dynamic SQL
Следующее
От: Tom Lane
Дата:
Сообщение: Re: configure can't detect proper pthread flags