From: Bruce Momjian Date: Tue, 26 Nov 2013 00:19:40 +0000 (-0500) Subject: Change SET LOCAL/CONSTRAINTS/TRANSACTION and ABORT behavior X-Git-Tag: REL9_4_BETA1~897 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a6542a4b6870a019cd952d055d2e7af2da2fe102;p=postgresql Change SET LOCAL/CONSTRAINTS/TRANSACTION and ABORT behavior Change SET LOCAL/CONSTRAINTS/TRANSACTION behavior outside of a transaction block from error (post-9.3) to warning. (Was nothing in <= 9.3.) Also change ABORT outside of a transaction block from notice to warning. --- diff --git a/doc/src/sgml/ref/abort.sgml b/doc/src/sgml/ref/abort.sgml index 246e8f8126..f3a2fa88ff 100644 --- a/doc/src/sgml/ref/abort.sgml +++ b/doc/src/sgml/ref/abort.sgml @@ -63,8 +63,7 @@ ABORT [ WORK | TRANSACTION ] - Issuing ABORT when not inside a transaction does - no harm, but it will provoke a warning message. + Issuing ABORT outside of a transaction block has no effect. diff --git a/doc/src/sgml/ref/rollback.sgml b/doc/src/sgml/ref/rollback.sgml index b26554567d..4f7962117c 100644 --- a/doc/src/sgml/ref/rollback.sgml +++ b/doc/src/sgml/ref/rollback.sgml @@ -59,8 +59,8 @@ ROLLBACK [ WORK | TRANSACTION ] - Issuing ROLLBACK when not inside a transaction does - no harm, but it will provoke a warning message. + Issuing ROLLBACK outside of a transaction + block has no effect. diff --git a/doc/src/sgml/ref/set.sgml b/doc/src/sgml/ref/set.sgml index 6290c9de70..5a84f697e6 100644 --- a/doc/src/sgml/ref/set.sgml +++ b/doc/src/sgml/ref/set.sgml @@ -110,9 +110,8 @@ SET [ SESSION | LOCAL ] TIME ZONE { timezone Specifies that the command takes effect for only the current transaction. After COMMIT or ROLLBACK, - the session-level setting takes effect again. - PostgreSQL reports an error if - SET LOCAL is used outside a transaction block. + the session-level setting takes effect again. This has no effect + outside of a transaction block. diff --git a/doc/src/sgml/ref/set_constraints.sgml b/doc/src/sgml/ref/set_constraints.sgml index 895a5fdbc0..a33190cca8 100644 --- a/doc/src/sgml/ref/set_constraints.sgml +++ b/doc/src/sgml/ref/set_constraints.sgml @@ -99,10 +99,7 @@ SET CONSTRAINTS { ALL | name [, ... This command only alters the behavior of constraints within the - current transaction. Thus, if you execute this command outside of a - transaction block - (BEGIN/COMMIT pair), it will - generate an error. + current transaction. This has no effect outside of a transaction block. diff --git a/doc/src/sgml/ref/set_transaction.sgml b/doc/src/sgml/ref/set_transaction.sgml index 391464ade8..e90ff4af72 100644 --- a/doc/src/sgml/ref/set_transaction.sgml +++ b/doc/src/sgml/ref/set_transaction.sgml @@ -185,7 +185,7 @@ SET SESSION CHARACTERISTICS AS TRANSACTION transa If SET TRANSACTION is executed without a prior START TRANSACTION or BEGIN, - it will generate an error. + it will have no effect. diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 0591f3fd56..bab048d38a 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); @@ -2948,6 +2950,26 @@ PreventTransactionChain(bool isTopLevel, const char *stmtType) /* all okay */ } +/* + * 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 * @@ -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 6a7bf0de7d..5895102b51 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 54d8078fe7..cbf3186789 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, diff --git a/src/include/access/xact.h b/src/include/access/xact.h index 835f6acbee..1d3e7d8938 100644 --- a/src/include/access/xact.h +++ b/src/include/access/xact.h @@ -245,6 +245,7 @@ extern char TransactionBlockStatusCode(void); extern void AbortOutOfAnyTransaction(void); extern void PreventTransactionChain(bool isTopLevel, const char *stmtType); extern void RequireTransactionChain(bool isTopLevel, const char *stmtType); +extern void WarnNoTransactionChain(bool isTopLevel, const char *stmtType); extern bool IsInTransactionChain(bool isTopLevel); extern void RegisterXactCallback(XactCallback callback, void *arg); extern void UnregisterXactCallback(XactCallback callback, void *arg); diff --git a/src/test/regress/expected/errors.out b/src/test/regress/expected/errors.out index fa0bd82819..4061512977 100644 --- a/src/test/regress/expected/errors.out +++ b/src/test/regress/expected/errors.out @@ -114,7 +114,7 @@ ERROR: column name "oid" conflicts with a system column name -- TRANSACTION STUFF -- not in a xact abort; -NOTICE: there is no transaction in progress +WARNING: there is no transaction in progress -- not in a xact end; WARNING: there is no transaction in progress diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out index 203fa6ef8e..4f0065cb7e 100644 --- a/src/test/regress/expected/guc.out +++ b/src/test/regress/expected/guc.out @@ -29,7 +29,7 @@ SELECT '2006-08-13 12:34:56'::timestamptz; -- SET LOCAL has no effect outside of a transaction SET LOCAL vacuum_cost_delay TO 50; -ERROR: SET LOCAL can only be used in transaction blocks +WARNING: SET LOCAL can only be used in transaction blocks SHOW vacuum_cost_delay; vacuum_cost_delay ------------------- @@ -37,7 +37,7 @@ SHOW vacuum_cost_delay; (1 row) SET LOCAL datestyle = 'SQL'; -ERROR: SET LOCAL can only be used in transaction blocks +WARNING: SET LOCAL can only be used in transaction blocks SHOW datestyle; DateStyle -----------