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

Reply via email to