aboutsummaryrefslogtreecommitdiff
path: root/src/backend/tcop/postgres.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/tcop/postgres.c')
-rw-r--r--src/backend/tcop/postgres.c57
1 files changed, 35 insertions, 22 deletions
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 8d3fecf6d6a..c10d891260c 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -883,10 +883,9 @@ exec_simple_query(const char *query_string)
ListCell *parsetree_item;
bool save_log_statement_stats = log_statement_stats;
bool was_logged = false;
- bool isTopLevel;
+ bool use_implicit_block;
char msec_str[32];
-
/*
* Report query to various monitoring facilities.
*/
@@ -947,13 +946,14 @@ exec_simple_query(const char *query_string)
MemoryContextSwitchTo(oldcontext);
/*
- * We'll tell PortalRun it's a top-level command iff there's exactly one
- * raw parsetree. If more than one, it's effectively a transaction block
- * and we want PreventTransactionChain to reject unsafe commands. (Note:
- * we're assuming that query rewrite cannot add commands that are
- * significant to PreventTransactionChain.)
+ * For historical reasons, if multiple SQL statements are given in a
+ * single "simple Query" message, we execute them as a single transaction,
+ * unless explicit transaction control commands are included to make
+ * portions of the list be separate transactions. To represent this
+ * behavior properly in the transaction machinery, we use an "implicit"
+ * transaction block.
*/
- isTopLevel = (list_length(parsetree_list) == 1);
+ use_implicit_block = (list_length(parsetree_list) > 1);
/*
* Run through the raw parsetree(s) and process each one.
@@ -1001,6 +1001,16 @@ exec_simple_query(const char *query_string)
/* Make sure we are in a transaction command */
start_xact_command();
+ /*
+ * If using an implicit transaction block, and we're not already in a
+ * transaction block, start an implicit block to force this statement
+ * to be grouped together with any following ones. (We must do this
+ * each time through the loop; otherwise, a COMMIT/ROLLBACK in the
+ * list would cause later statements to not be grouped.)
+ */
+ if (use_implicit_block)
+ BeginImplicitTransactionBlock();
+
/* If we got a cancel signal in parsing or prior command, quit */
CHECK_FOR_INTERRUPTS();
@@ -1098,7 +1108,7 @@ exec_simple_query(const char *query_string)
*/
(void) PortalRun(portal,
FETCH_ALL,
- isTopLevel,
+ true, /* always top level */
true,
receiver,
receiver,
@@ -1108,15 +1118,7 @@ exec_simple_query(const char *query_string)
PortalDrop(portal, false);
- if (IsA(parsetree->stmt, 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 (lnext(parsetree_item) == NULL)
{
/*
* If this is the last parsetree of the query string, close down
@@ -1124,9 +1126,18 @@ exec_simple_query(const char *query_string)
* is so that any end-of-transaction errors are reported before
* the command-complete message is issued, to avoid confusing
* clients who will expect either a command-complete message or an
- * error, not one and then the other. But for compatibility with
- * historical Postgres behavior, we do not force a transaction
- * boundary between queries appearing in a single query string.
+ * error, not one and then the other. Also, if we're using an
+ * implicit transaction block, we must close that out first.
+ */
+ if (use_implicit_block)
+ EndImplicitTransactionBlock();
+ finish_xact_command();
+ }
+ else if (IsA(parsetree->stmt, TransactionStmt))
+ {
+ /*
+ * If this was a transaction control statement, commit it. We will
+ * start a new xact command for the next command.
*/
finish_xact_command();
}
@@ -1149,7 +1160,9 @@ exec_simple_query(const char *query_string)
} /* end loop over parsetrees */
/*
- * Close down transaction statement, if one is open.
+ * Close down transaction statement, if one is open. (This will only do
+ * something if the parsetree list was empty; otherwise the last loop
+ * iteration already did it.)
*/
finish_xact_command();