aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/transam/xact.c14
-rw-r--r--src/backend/tcop/postgres.c52
-rw-r--r--src/include/access/xact.h6
3 files changed, 46 insertions, 26 deletions
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index bd60b55574c..594d8da2cdc 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -3453,6 +3453,9 @@ AbortCurrentTransaction(void)
* could issue more commands and possibly cause a failure after the statement
* completes). Subtransactions are verboten too.
*
+ * We must also set XACT_FLAGS_NEEDIMMEDIATECOMMIT in MyXactFlags, to ensure
+ * that postgres.c follows through by committing after the statement is done.
+ *
* isTopLevel: passed down from ProcessUtility to determine whether we are
* inside a function. (We will always fail if this is false, but it's
* convenient to centralize the check here instead of making callers do it.)
@@ -3494,7 +3497,9 @@ PreventInTransactionBlock(bool isTopLevel, const char *stmtType)
if (CurrentTransactionState->blockState != TBLOCK_DEFAULT &&
CurrentTransactionState->blockState != TBLOCK_STARTED)
elog(FATAL, "cannot prevent transaction chain");
- /* all okay */
+
+ /* All okay. Set the flag to make sure the right thing happens later. */
+ MyXactFlags |= XACT_FLAGS_NEEDIMMEDIATECOMMIT;
}
/*
@@ -3591,6 +3596,13 @@ IsInTransactionBlock(bool isTopLevel)
CurrentTransactionState->blockState != TBLOCK_STARTED)
return true;
+ /*
+ * If we tell the caller we're not in a transaction block, then inform
+ * postgres.c that it had better commit when the statement is done.
+ * Otherwise our report could be a lie.
+ */
+ MyXactFlags |= XACT_FLAGS_NEEDIMMEDIATECOMMIT;
+
return false;
}
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index f84b2fa54e0..06dfe115e48 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -1285,6 +1285,13 @@ exec_simple_query(const char *query_string)
else
{
/*
+ * We had better not see XACT_FLAGS_NEEDIMMEDIATECOMMIT set if
+ * we're not calling finish_xact_command(). (The implicit
+ * transaction block should have prevented it from getting set.)
+ */
+ Assert(!(MyXactFlags & XACT_FLAGS_NEEDIMMEDIATECOMMIT));
+
+ /*
* We need a CommandCounterIncrement after every query, except
* those that start or end a transaction block.
*/
@@ -2099,32 +2106,16 @@ exec_execute_message(const char *portal_name, long max_rows)
/*
* We must copy the sourceText and prepStmtName into MessageContext in
- * case the portal is destroyed during finish_xact_command. Can avoid the
- * copy if it's not an xact command, though.
+ * case the portal is destroyed during finish_xact_command. We do not
+ * make a copy of the portalParams though, preferring to just not print
+ * them in that case.
*/
- if (is_xact_command)
- {
- sourceText = pstrdup(portal->sourceText);
- if (portal->prepStmtName)
- prepStmtName = pstrdup(portal->prepStmtName);
- else
- prepStmtName = "<unnamed>";
-
- /*
- * An xact command shouldn't have any parameters, which is a good
- * thing because they wouldn't be around after finish_xact_command.
- */
- portalParams = NULL;
- }
+ sourceText = pstrdup(portal->sourceText);
+ if (portal->prepStmtName)
+ prepStmtName = pstrdup(portal->prepStmtName);
else
- {
- sourceText = portal->sourceText;
- if (portal->prepStmtName)
- prepStmtName = portal->prepStmtName;
- else
- prepStmtName = "<unnamed>";
- portalParams = portal->portalParams;
- }
+ prepStmtName = "<unnamed>";
+ portalParams = portal->portalParams;
/*
* Report query to various monitoring facilities.
@@ -2223,13 +2214,24 @@ exec_execute_message(const char *portal_name, long max_rows)
if (completed)
{
- if (is_xact_command)
+ if (is_xact_command || (MyXactFlags & XACT_FLAGS_NEEDIMMEDIATECOMMIT))
{
/*
* If this was a transaction control statement, commit it. We
* will start a new xact command for the next command (if any).
+ * Likewise if the statement required immediate commit. Without
+ * this provision, we wouldn't force commit until Sync is
+ * received, which creates a hazard if the client tries to
+ * pipeline immediate-commit statements.
*/
finish_xact_command();
+
+ /*
+ * These commands typically don't have any parameters, and even if
+ * one did we couldn't print them now because the storage went
+ * away during finish_xact_command. So pretend there were none.
+ */
+ portalParams = NULL;
}
else
{
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 4794941df31..65616ca2f79 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -108,6 +108,12 @@ extern PGDLLIMPORT int MyXactFlags;
#define XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK (1U << 1)
/*
+ * XACT_FLAGS_NEEDIMMEDIATECOMMIT - records whether the top level statement
+ * is one that requires immediate commit, such as CREATE DATABASE.
+ */
+#define XACT_FLAGS_NEEDIMMEDIATECOMMIT (1U << 2)
+
+/*
* start- and end-of-transaction callbacks for dynamically loaded modules
*/
typedef enum