On Wed, Nov 20, 2013 at 10:16:00AM -0500, Bruce Momjian wrote: > > > The attached patch changes ABORT from NOTICE to WARNING, and documents > > > that all other are errors. This "top-level" logic idea came from Robert > > > Haas, and it has some level of consistency. > > > > This patch utterly fails to address my complaint. > > > > More to the point, I think it's a waste of time to make these sorts of > > adjustments. The only thanks you're likely to get for it is complaints > > about cross-version behavioral changes. Also, you're totally ignoring > > the thought that these different message levels might've been selected > > intentionally, back when the code was written. Since there have been > > no field complaints about the inconsistency, what's your hurry to > > change it? See Emerson. > > My problem was that they issued _no_ message at all. I am fine with > them issuing a warning if that's what people prefer. As they are all > SET commands, they will be consistent.
OK, here is a patch which changes ABORT from NOTICE to WARNING, and SET from ERROR (which is new in 9.4) to WARNING. -- Bruce Momjian <br...@momjian.us> http://momjian.us EnterpriseDB http://enterprisedb.com + Everyone has their own god. +
diff --git a/doc/src/sgml/ref/abort.sgml b/doc/src/sgml/ref/abort.sgml new file mode 100644 index 246e8f8..f3a2fa8 *** a/doc/src/sgml/ref/abort.sgml --- b/doc/src/sgml/ref/abort.sgml *************** ABORT [ WORK | TRANSACTION ] *** 63,70 **** </para> <para> ! Issuing <command>ABORT</> when not inside a transaction does ! no harm, but it will provoke a warning message. </para> </refsect1> --- 63,69 ---- </para> <para> ! Issuing <command>ABORT</> outside of a transaction block has no effect. </para> </refsect1> diff --git a/doc/src/sgml/ref/rollback.sgml b/doc/src/sgml/ref/rollback.sgml new file mode 100644 index b265545..4f79621 *** a/doc/src/sgml/ref/rollback.sgml --- b/doc/src/sgml/ref/rollback.sgml *************** ROLLBACK [ WORK | TRANSACTION ] *** 59,66 **** </para> <para> ! Issuing <command>ROLLBACK</> when not inside a transaction does ! no harm, but it will provoke a warning message. </para> </refsect1> --- 59,66 ---- </para> <para> ! Issuing <command>ROLLBACK</> outside of a transaction ! block has no effect. </para> </refsect1> diff --git a/doc/src/sgml/ref/set.sgml b/doc/src/sgml/ref/set.sgml new file mode 100644 index 6290c9d..5a84f69 *** a/doc/src/sgml/ref/set.sgml --- b/doc/src/sgml/ref/set.sgml *************** SET [ SESSION | LOCAL ] TIME ZONE { <rep *** 110,118 **** <para> Specifies that the command takes effect for only the current transaction. After <command>COMMIT</> or <command>ROLLBACK</>, ! the session-level setting takes effect again. ! <productname>PostgreSQL</productname> reports an error if ! <command>SET LOCAL</> is used outside a transaction block. </para> </listitem> </varlistentry> --- 110,117 ---- <para> Specifies that the command takes effect for only the current transaction. After <command>COMMIT</> or <command>ROLLBACK</>, ! the session-level setting takes effect again. This has no effect ! outside of a transaction block. </para> </listitem> </varlistentry> diff --git a/doc/src/sgml/ref/set_constraints.sgml b/doc/src/sgml/ref/set_constraints.sgml new file mode 100644 index 895a5fd..a33190c *** a/doc/src/sgml/ref/set_constraints.sgml --- b/doc/src/sgml/ref/set_constraints.sgml *************** SET CONSTRAINTS { ALL | <replaceable cla *** 99,108 **** <para> This command only alters the behavior of constraints within the ! current transaction. Thus, if you execute this command outside of a ! transaction block ! (<command>BEGIN</command>/<command>COMMIT</command> pair), it will ! generate an error. </para> </refsect1> --- 99,105 ---- <para> This command only alters the behavior of constraints within the ! current transaction. This has no effect outside of a transaction block. </para> </refsect1> diff --git a/doc/src/sgml/ref/set_transaction.sgml b/doc/src/sgml/ref/set_transaction.sgml new file mode 100644 index 391464a..e90ff4a *** a/doc/src/sgml/ref/set_transaction.sgml --- b/doc/src/sgml/ref/set_transaction.sgml *************** SET SESSION CHARACTERISTICS AS TRANSACTI *** 185,191 **** <para> If <command>SET TRANSACTION</command> is executed without a prior <command>START TRANSACTION</command> or <command>BEGIN</command>, ! it will generate an error. </para> <para> --- 185,191 ---- <para> If <command>SET TRANSACTION</command> is executed without a prior <command>START TRANSACTION</command> or <command>BEGIN</command>, ! it will have no effect. </para> <para> diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c new file mode 100644 index 0591f3f..2cdcc98 *** a/src/backend/access/transam/xact.c --- b/src/backend/access/transam/xact.c *************** PreventTransactionChain(bool isTopLevel, *** 2961,2972 **** * 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. */ void ! RequireTransactionChain(bool isTopLevel, const char *stmtType) { /* * xact block already started? --- 2961,2976 ---- * use of the current statement's results. Likewise subtransactions. * Thus this is an inverse for PreventTransactionChain. * + * While top-level transaction control commands (BEGIN/COMMIT/ABORT) and + * SET that have no effect issue warnings, all other no-effect commands + * generate errors. + * * isTopLevel: passed down from ProcessUtility to determine whether we are * inside a function. * stmtType: statement type name, for error messages. */ void ! RequireTransactionChain(bool isTopLevel, bool throwError, const char *stmtType) { /* * xact block already started? *************** RequireTransactionChain(bool isTopLevel, *** 2986,2996 **** if (!isTopLevel) return; ! ereport(ERROR, (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION), /* translator: %s represents an SQL statement name */ errmsg("%s can only be used in transaction blocks", stmtType))); } /* --- 2990,3001 ---- if (!isTopLevel) return; ! 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; } /* *************** UserAbortTransactionBlock(void) *** 3425,3436 **** /* * The user issued ABORT when not inside a transaction. Issue a ! * NOTICE and go to abort state. The upcoming call to * CommitTransactionCommand() will then put us back into the * default state. */ case TBLOCK_STARTED: ! ereport(NOTICE, (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION), errmsg("there is no transaction in progress"))); s->blockState = TBLOCK_ABORT_PENDING; --- 3430,3441 ---- /* * The user issued ABORT when not inside a transaction. Issue a ! * WARNING and go to abort state. The upcoming call to * CommitTransactionCommand() will then put us back into the * default state. */ case TBLOCK_STARTED: ! 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/commands/portalcmds.c b/src/backend/commands/portalcmds.c new file mode 100644 index 5c3f42c..c3c3e20 *** a/src/backend/commands/portalcmds.c --- b/src/backend/commands/portalcmds.c *************** PerformCursorOpen(PlannedStmt *stmt, Par *** 66,72 **** * user-visible effect). */ if (!(cstmt->options & CURSOR_OPT_HOLD)) ! RequireTransactionChain(isTopLevel, "DECLARE CURSOR"); /* * Create a portal and copy the plan and queryString into its memory. --- 66,72 ---- * user-visible effect). */ if (!(cstmt->options & CURSOR_OPT_HOLD)) ! RequireTransactionChain(isTopLevel, true, "DECLARE CURSOR"); /* * Create a portal and copy the plan and queryString into its memory. diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c new file mode 100644 index 6a7bf0d..6d4b18b *** a/src/backend/tcop/utility.c --- b/src/backend/tcop/utility.c *************** standard_ProcessUtility(Node *parsetree, *** 461,467 **** ListCell *cell; char *name = NULL; ! RequireTransactionChain(isTopLevel, "SAVEPOINT"); foreach(cell, stmt->options) { --- 461,467 ---- ListCell *cell; char *name = NULL; ! RequireTransactionChain(isTopLevel, true, "SAVEPOINT"); foreach(cell, stmt->options) { *************** standard_ProcessUtility(Node *parsetree, *** 478,489 **** break; case TRANS_STMT_RELEASE: ! RequireTransactionChain(isTopLevel, "RELEASE SAVEPOINT"); ReleaseSavepoint(stmt->options); break; case TRANS_STMT_ROLLBACK_TO: ! RequireTransactionChain(isTopLevel, "ROLLBACK TO SAVEPOINT"); RollbackToSavepoint(stmt->options); /* --- 478,489 ---- break; case TRANS_STMT_RELEASE: ! RequireTransactionChain(isTopLevel, true, "RELEASE SAVEPOINT"); ReleaseSavepoint(stmt->options); break; case TRANS_STMT_ROLLBACK_TO: ! RequireTransactionChain(isTopLevel, true, "ROLLBACK TO SAVEPOINT"); RollbackToSavepoint(stmt->options); /* *************** standard_ProcessUtility(Node *parsetree, *** 749,760 **** * Since the lock would just get dropped immediately, LOCK TABLE * outside a transaction block is presumed to be user error. */ ! RequireTransactionChain(isTopLevel, "LOCK TABLE"); LockTableCommand((LockStmt *) parsetree); break; case T_ConstraintsSetStmt: ! RequireTransactionChain(isTopLevel, "SET CONSTRAINTS"); AfterTriggerSetState((ConstraintsSetStmt *) parsetree); break; --- 749,760 ---- * Since the lock would just get dropped immediately, LOCK TABLE * outside a transaction block is presumed to be user error. */ ! RequireTransactionChain(isTopLevel, true, "LOCK TABLE"); LockTableCommand((LockStmt *) parsetree); break; case T_ConstraintsSetStmt: ! RequireTransactionChain(isTopLevel, false, "SET CONSTRAINTS"); AfterTriggerSetState((ConstraintsSetStmt *) parsetree); break; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c new file mode 100644 index 54d8078..6dffa12 *** a/src/backend/utils/misc/guc.c --- b/src/backend/utils/misc/guc.c *************** ExecSetVariableStmt(VariableSetStmt *stm *** 6274,6280 **** case VAR_SET_VALUE: case VAR_SET_CURRENT: if (stmt->is_local) ! RequireTransactionChain(isTopLevel, "SET LOCAL"); (void) set_config_option(stmt->name, ExtractSetVariableArgs(stmt), (superuser() ? PGC_SUSET : PGC_USERSET), --- 6274,6280 ---- case VAR_SET_VALUE: case VAR_SET_CURRENT: if (stmt->is_local) ! RequireTransactionChain(isTopLevel, false, "SET LOCAL"); (void) set_config_option(stmt->name, ExtractSetVariableArgs(stmt), (superuser() ? PGC_SUSET : PGC_USERSET), *************** ExecSetVariableStmt(VariableSetStmt *stm *** 6295,6301 **** { ListCell *head; ! RequireTransactionChain(isTopLevel, "SET TRANSACTION"); foreach(head, stmt->args) { --- 6295,6301 ---- { ListCell *head; ! RequireTransactionChain(isTopLevel, false, "SET TRANSACTION"); foreach(head, stmt->args) { *************** ExecSetVariableStmt(VariableSetStmt *stm *** 6346,6352 **** (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("SET LOCAL TRANSACTION SNAPSHOT is not implemented"))); ! RequireTransactionChain(isTopLevel, "SET TRANSACTION"); Assert(IsA(con, A_Const)); Assert(nodeTag(&con->val) == T_String); ImportSnapshot(strVal(&con->val)); --- 6346,6352 ---- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("SET LOCAL TRANSACTION SNAPSHOT is not implemented"))); ! RequireTransactionChain(isTopLevel, false, "SET TRANSACTION"); Assert(IsA(con, A_Const)); Assert(nodeTag(&con->val) == T_String); ImportSnapshot(strVal(&con->val)); *************** ExecSetVariableStmt(VariableSetStmt *stm *** 6357,6367 **** break; case VAR_SET_DEFAULT: if (stmt->is_local) ! RequireTransactionChain(isTopLevel, "SET LOCAL"); /* fall through */ case VAR_RESET: if (strcmp(stmt->name, "transaction_isolation") == 0) ! RequireTransactionChain(isTopLevel, "RESET TRANSACTION"); (void) set_config_option(stmt->name, NULL, --- 6357,6367 ---- break; case VAR_SET_DEFAULT: if (stmt->is_local) ! RequireTransactionChain(isTopLevel, false, "SET LOCAL"); /* fall through */ case VAR_RESET: if (strcmp(stmt->name, "transaction_isolation") == 0) ! RequireTransactionChain(isTopLevel, false, "RESET TRANSACTION"); (void) set_config_option(stmt->name, NULL, diff --git a/src/include/access/xact.h b/src/include/access/xact.h new file mode 100644 index 835f6ac..1265bea *** a/src/include/access/xact.h --- b/src/include/access/xact.h *************** extern bool IsTransactionOrTransactionBl *** 244,250 **** 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 bool IsInTransactionChain(bool isTopLevel); extern void RegisterXactCallback(XactCallback callback, void *arg); extern void UnregisterXactCallback(XactCallback callback, void *arg); --- 244,251 ---- extern char TransactionBlockStatusCode(void); extern void AbortOutOfAnyTransaction(void); extern void PreventTransactionChain(bool isTopLevel, const char *stmtType); ! extern void RequireTransactionChain(bool isTopLevel, bool throwError, ! 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 new file mode 100644 index fa0bd82..4061512 *** a/src/test/regress/expected/errors.out --- b/src/test/regress/expected/errors.out *************** ERROR: column name "oid" conflicts with *** 114,120 **** -- TRANSACTION STUFF -- not in a xact abort; ! NOTICE: there is no transaction in progress -- not in a xact end; WARNING: there is no transaction in progress --- 114,120 ---- -- TRANSACTION STUFF -- not in a xact abort; ! 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 new file mode 100644 index 203fa6e..4f0065c *** a/src/test/regress/expected/guc.out --- b/src/test/regress/expected/guc.out *************** SELECT '2006-08-13 12:34:56'::timestampt *** 29,35 **** -- 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 SHOW vacuum_cost_delay; vacuum_cost_delay ------------------- --- 29,35 ---- -- SET LOCAL has no effect outside of a transaction SET LOCAL vacuum_cost_delay TO 50; ! WARNING: SET LOCAL can only be used in transaction blocks SHOW vacuum_cost_delay; vacuum_cost_delay ------------------- *************** SHOW vacuum_cost_delay; *** 37,43 **** (1 row) SET LOCAL datestyle = 'SQL'; ! ERROR: SET LOCAL can only be used in transaction blocks SHOW datestyle; DateStyle ----------- --- 37,43 ---- (1 row) SET LOCAL datestyle = 'SQL'; ! WARNING: SET LOCAL can only be used in transaction blocks SHOW datestyle; DateStyle -----------
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers