aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/transam/xact.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access/transam/xact.c')
-rw-r--r--src/backend/access/transam/xact.c65
1 files changed, 61 insertions, 4 deletions
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 046486a6ccc..4687578fedd 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.133 2002/10/21 19:46:45 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.134 2002/10/21 22:06:18 tgl Exp $
*
* NOTES
* Transaction aborts can now occur two ways:
@@ -1280,9 +1280,12 @@ CommitTransactionCommand(bool forceCommit)
*
* Autocommit mode is forced by either a true forceCommit
* parameter to me, or a true preventChain parameter to the
- * preceding StartTransactionCommand call. This is needed so
- * that commands like VACUUM can ensure that the right things
- * happen.
+ * preceding StartTransactionCommand call, or a
+ * PreventTransactionChain call during the transaction.
+ * (The parameters could be omitted, but it turns out most
+ * callers of StartTransactionCommand/CommitTransactionCommand
+ * want to force autocommit, so making them all call
+ * PreventTransactionChain would just be extra notation.)
*/
case TBLOCK_DEFAULT:
if (autocommit || forceCommit || suppressChain)
@@ -1429,6 +1432,60 @@ AbortCurrentTransaction(void)
}
}
+/* --------------------------------
+ * PreventTransactionChain
+ *
+ * This routine is to be called by statements that must not run inside
+ * a transaction block, typically because they have non-rollback-able
+ * side effects or do internal commits.
+ *
+ * If we have already started a transaction block, issue an error; also issue
+ * an error if we appear to be running inside a user-defined function (which
+ * could issue more commands and possibly cause a failure after the statement
+ * completes). In autocommit-off mode, we allow the statement if a block is
+ * not already started, and force the statement to be autocommitted despite
+ * the mode.
+ *
+ * stmtNode: pointer to parameter block for statement; this is used in
+ * a very klugy way to determine whether we are inside a function.
+ * stmtType: statement type name for error messages.
+ * --------------------------------
+ */
+void
+PreventTransactionChain(void *stmtNode, const char *stmtType)
+{
+ /*
+ * xact block already started?
+ */
+ if (IsTransactionBlock())
+ {
+ /* translator: %s represents an SQL statement name */
+ elog(ERROR, "%s cannot run inside a transaction block", stmtType);
+ }
+ /*
+ * Are we inside a function call? If the statement's parameter block
+ * was allocated in QueryContext, assume it is an interactive command.
+ * Otherwise assume it is coming from a function.
+ */
+ if (!MemoryContextContains(QueryContext, stmtNode))
+ {
+ /* translator: %s represents an SQL statement name */
+ elog(ERROR, "%s cannot be executed from a function", stmtType);
+ }
+ /* If we got past IsTransactionBlock test, should be in default state */
+ if (CurrentTransactionState->blockState != TBLOCK_DEFAULT)
+ elog(ERROR, "PreventTransactionChain: can't prevent chain");
+ /* okay to set the flag */
+ suppressChain = true;
+ /* If we're in autocommit-off node, generate a notice */
+ if (!autocommit)
+ {
+ /* translator: %s represents an SQL statement name */
+ elog(NOTICE, "%s will be committed automatically", stmtType);
+ }
+}
+
+
/* ----------------------------------------------------------------
* transaction block support
* ----------------------------------------------------------------