diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/access/transam/xact.c | 37 | ||||
-rw-r--r-- | src/backend/tcop/utility.c | 2 | ||||
-rw-r--r-- | src/backend/utils/misc/guc.c | 10 |
3 files changed, 36 insertions, 13 deletions
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 0591f3fd562..bab048d38a1 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -265,6 +265,8 @@ static void CallSubXactCallbacks(SubXactEvent event, SubTransactionId mySubid, SubTransactionId parentSubid); 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); @@ -2949,6 +2951,26 @@ PreventTransactionChain(bool isTopLevel, const char *stmtType) } /* + * These two functions allow for warnings or errors if a command is + * executed outside of a transaction block. + * + * While top-level transaction control commands (BEGIN/COMMIT/ABORT) and + * SET that have no effect issue warnings, all other no-effect commands + * generate errors. + */ +void +WarnNoTransactionChain(bool isTopLevel, const char *stmtType) +{ + CheckTransactionChain(isTopLevel, false, stmtType); +} + +void +RequireTransactionChain(bool isTopLevel, const char *stmtType) +{ + CheckTransactionChain(isTopLevel, true, stmtType); +} + +/* * RequireTransactionChain * * This routine is to be called by statements that must run inside @@ -2957,16 +2979,16 @@ PreventTransactionChain(bool isTopLevel, const char *stmtType) * is presumably an error). DECLARE CURSOR is an example. * * If we appear to be running inside a user-defined function, we do not - * issue an error, since the function could issue more commands that make + * issue anything, since the function could issue more commands that make * use of the current statement's results. Likewise subtransactions. * Thus this is an inverse for PreventTransactionChain. * * isTopLevel: passed down from ProcessUtility to determine whether we are * inside a function. - * stmtType: statement type name, for error messages. + * stmtType: statement type name, for warning or error messages. */ -void -RequireTransactionChain(bool isTopLevel, const char *stmtType) +static void +CheckTransactionChain(bool isTopLevel, bool throwError, const char *stmtType) { /* * xact block already started? @@ -2986,11 +3008,12 @@ RequireTransactionChain(bool isTopLevel, const char *stmtType) if (!isTopLevel) return; - ereport(ERROR, + ereport(throwError ? ERROR : WARNING, (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION), /* translator: %s represents an SQL statement name */ errmsg("%s can only be used in transaction blocks", stmtType))); + return; } /* @@ -3425,12 +3448,12 @@ UserAbortTransactionBlock(void) /* * The user issued ABORT when not inside a transaction. Issue a - * NOTICE and go to abort state. The upcoming call to + * WARNING and go to abort state. The upcoming call to * CommitTransactionCommand() will then put us back into the * default state. */ case TBLOCK_STARTED: - ereport(NOTICE, + ereport(WARNING, (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION), errmsg("there is no transaction in progress"))); s->blockState = TBLOCK_ABORT_PENDING; diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 6a7bf0de7d7..5895102b518 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -754,7 +754,7 @@ standard_ProcessUtility(Node *parsetree, break; case T_ConstraintsSetStmt: - RequireTransactionChain(isTopLevel, "SET CONSTRAINTS"); + WarnNoTransactionChain(isTopLevel, "SET CONSTRAINTS"); AfterTriggerSetState((ConstraintsSetStmt *) parsetree); break; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 54d8078fe7a..cbf3186789c 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -6274,7 +6274,7 @@ ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel) case VAR_SET_VALUE: case VAR_SET_CURRENT: if (stmt->is_local) - RequireTransactionChain(isTopLevel, "SET LOCAL"); + WarnNoTransactionChain(isTopLevel, "SET LOCAL"); (void) set_config_option(stmt->name, ExtractSetVariableArgs(stmt), (superuser() ? PGC_SUSET : PGC_USERSET), @@ -6295,7 +6295,7 @@ ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel) { ListCell *head; - RequireTransactionChain(isTopLevel, "SET TRANSACTION"); + WarnNoTransactionChain(isTopLevel, "SET TRANSACTION"); foreach(head, stmt->args) { @@ -6346,7 +6346,7 @@ ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("SET LOCAL TRANSACTION SNAPSHOT is not implemented"))); - RequireTransactionChain(isTopLevel, "SET TRANSACTION"); + WarnNoTransactionChain(isTopLevel, "SET TRANSACTION"); Assert(IsA(con, A_Const)); Assert(nodeTag(&con->val) == T_String); ImportSnapshot(strVal(&con->val)); @@ -6357,11 +6357,11 @@ ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel) break; case VAR_SET_DEFAULT: if (stmt->is_local) - RequireTransactionChain(isTopLevel, "SET LOCAL"); + WarnNoTransactionChain(isTopLevel, "SET LOCAL"); /* fall through */ case VAR_RESET: if (strcmp(stmt->name, "transaction_isolation") == 0) - RequireTransactionChain(isTopLevel, "RESET TRANSACTION"); + WarnNoTransactionChain(isTopLevel, "RESET TRANSACTION"); (void) set_config_option(stmt->name, NULL, |