diff --git a/doc/src/sgml/ref/declare.sgml b/doc/src/sgml/ref/declare.sgml
new file mode 100644
index d500faa..7b8c6b6
*** a/doc/src/sgml/ref/declare.sgml
--- b/doc/src/sgml/ref/declare.sgml
*************** DECLARE <replaceable class="parameter">n
*** 179,187 ****
      created by this command can only be used within the current
      transaction.  Thus, <command>DECLARE</> without <literal>WITH
      HOLD</literal> is useless outside a transaction block: the cursor would
!     survive only to the completion of the statement.  Therefore
!     <productname>PostgreSQL</productname> reports an error if such a
!     command is used outside a transaction block.
      Use
      <xref linkend="sql-begin"> and
      <xref linkend="sql-commit">
--- 179,185 ----
      created by this command can only be used within the current
      transaction.  Thus, <command>DECLARE</> without <literal>WITH
      HOLD</literal> is useless outside a transaction block: the cursor would
!     survive only to the completion of the statement.
      Use
      <xref linkend="sql-begin"> and
      <xref linkend="sql-commit">
diff --git a/doc/src/sgml/ref/lock.sgml b/doc/src/sgml/ref/lock.sgml
new file mode 100644
index 95d6767..6a0ad20
*** a/doc/src/sgml/ref/lock.sgml
--- b/doc/src/sgml/ref/lock.sgml
*************** LOCK [ TABLE ] [ ONLY ] <replaceable cla
*** 168,176 ****
  
     <para>
      <command>LOCK TABLE</> is useless outside a transaction block: the lock
!     would remain held only to the completion of the statement.  Therefore
!     <productname>PostgreSQL</productname> reports an error if <command>LOCK</>
!     is used outside a transaction block.
      Use
      <xref linkend="sql-begin"> and
      <xref linkend="sql-commit">
--- 168,174 ----
  
     <para>
      <command>LOCK TABLE</> is useless outside a transaction block: the lock
!     would remain held only to the completion of the statement.
      Use
      <xref linkend="sql-begin"> and
      <xref linkend="sql-commit">
diff --git a/doc/src/sgml/ref/set.sgml b/doc/src/sgml/ref/set.sgml
new file mode 100644
index 6290c9d..aaaf186
*** a/doc/src/sgml/ref/set.sgml
--- b/doc/src/sgml/ref/set.sgml
*************** SET [ SESSION | LOCAL ] TIME ZONE { <rep
*** 111,117 ****
        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>
--- 111,117 ----
        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> generates a warning if
        <command>SET LOCAL</> is used outside a transaction block.
       </para>
      </listitem>
diff --git a/doc/src/sgml/ref/set_constraints.sgml b/doc/src/sgml/ref/set_constraints.sgml
new file mode 100644
index 895a5fd..2fd228c
*** 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 and is useless outside 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..a568ab7
*** a/doc/src/sgml/ref/set_transaction.sgml
--- b/doc/src/sgml/ref/set_transaction.sgml
*************** SET SESSION CHARACTERISTICS AS TRANSACTI
*** 183,194 ****
    <title>Notes</title>
  
    <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>
     It is possible to dispense with <command>SET TRANSACTION</command>
     by instead specifying the desired <replaceable
     class="parameter">transaction_modes</replaceable> in
--- 183,188 ----
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
new file mode 100644
index 0591f3f..4e492c4
*** a/src/backend/access/transam/xact.c
--- b/src/backend/access/transam/xact.c
*************** PreventTransactionChain(bool isTopLevel,
*** 2949,2955 ****
  }
  
  /*
!  *	RequireTransactionChain
   *
   *	This routine is to be called by statements that must run inside
   *	a transaction block, because they have no effects that persist past
--- 2949,2955 ----
  }
  
  /*
!  *	IsTransactionChain
   *
   *	This routine is to be called by statements that must run inside
   *	a transaction block, because they have no effects that persist past
*************** PreventTransactionChain(bool isTopLevel,
*** 2963,2996 ****
   *
   *	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?
  	 */
  	if (IsTransactionBlock())
! 		return;
  
  	/*
  	 * subtransaction?
  	 */
  	if (IsSubTransaction())
! 		return;
  
  	/*
  	 * inside a function call?
  	 */
  	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)));
  }
  
  /*
--- 2963,2997 ----
   *
   *	isTopLevel: passed down from ProcessUtility to determine whether we are
   *	inside a function.
!  *	stmtType: statement type name, for warning messages.
   */
! bool
! IsTransactionChain(bool isTopLevel, const char *stmtType)
  {
  	/*
  	 * xact block already started?
  	 */
  	if (IsTransactionBlock())
! 		return true;
  
  	/*
  	 * subtransaction?
  	 */
  	if (IsSubTransaction())
! 		return true;
  
  	/*
  	 * inside a function call?
  	 */
  	if (!isTopLevel)
! 		return true;
  
! 	ereport(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 false;
  }
  
  /*
diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c
new file mode 100644
index 5c3f42c..6be3fa1
*** 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))
! 		IsTransactionChain(isTopLevel, "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..0566e59
*** a/src/backend/tcop/utility.c
--- b/src/backend/tcop/utility.c
*************** standard_ProcessUtility(Node *parsetree,
*** 461,490 ****
  							ListCell   *cell;
  							char	   *name = NULL;
  
! 							RequireTransactionChain(isTopLevel, "SAVEPOINT");
! 
! 							foreach(cell, stmt->options)
  							{
! 								DefElem    *elem = lfirst(cell);
! 
! 								if (strcmp(elem->defname, "savepoint_name") == 0)
! 									name = strVal(elem->arg);
  							}
- 
- 							Assert(PointerIsValid(name));
- 
- 							DefineSavepoint(name);
  						}
  						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);
  
  						/*
  						 * CommitTransactionCommand is in charge of
--- 461,491 ----
  							ListCell   *cell;
  							char	   *name = NULL;
  
! 							if (IsTransactionChain(isTopLevel, "SAVEPOINT"))
  							{
! 								foreach(cell, stmt->options)
! 								{
! 									DefElem    *elem = lfirst(cell);
! 	
! 									if (strcmp(elem->defname, "savepoint_name") == 0)
! 										name = strVal(elem->arg);
! 								}
! 	
! 								Assert(PointerIsValid(name));
! 	
! 								DefineSavepoint(name);
  							}
  						}
  						break;
  
  					case TRANS_STMT_RELEASE:
! 						if (IsTransactionChain(isTopLevel, "RELEASE SAVEPOINT"))
! 							ReleaseSavepoint(stmt->options);
  						break;
  
  					case TRANS_STMT_ROLLBACK_TO:
! 						if (IsTransactionChain(isTopLevel, "ROLLBACK TO SAVEPOINT"))
! 							RollbackToSavepoint(stmt->options);
  
  						/*
  						 * CommitTransactionCommand is in charge of
*************** 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;
  
--- 750,761 ----
  			 * Since the lock would just get dropped immediately, LOCK TABLE
  			 * outside a transaction block is presumed to be user error.
  			 */
! 			IsTransactionChain(isTopLevel, "LOCK TABLE");
  			LockTableCommand((LockStmt *) parsetree);
  			break;
  
  		case T_ConstraintsSetStmt:
! 			IsTransactionChain(isTopLevel, "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..2437007
*** 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)
! 				IsTransactionChain(isTopLevel, "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;
  
! 				IsTransactionChain(isTopLevel, "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")));
  
! 				IsTransactionChain(isTopLevel, "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)
! 				IsTransactionChain(isTopLevel, "SET LOCAL");
  			/* fall through */
  		case VAR_RESET:
  			if (strcmp(stmt->name, "transaction_isolation") == 0)
! 				IsTransactionChain(isTopLevel, "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..690b50d
*** 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,250 ----
  extern char TransactionBlockStatusCode(void);
  extern void AbortOutOfAnyTransaction(void);
  extern void PreventTransactionChain(bool isTopLevel, const char *stmtType);
! extern bool IsTransactionChain(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/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 
  -----------
diff --git a/src/test/regress/expected/transactions.out b/src/test/regress/expected/transactions.out
new file mode 100644
index 5c84ec5..45bbe8a
*** a/src/test/regress/expected/transactions.out
--- b/src/test/regress/expected/transactions.out
*************** SELECT a FROM savepoints WHERE a BETWEEN
*** 363,373 ****
  DROP TABLE savepoints;
  -- only in a transaction block:
  SAVEPOINT one;
! ERROR:  SAVEPOINT can only be used in transaction blocks
  ROLLBACK TO SAVEPOINT one;
! ERROR:  ROLLBACK TO SAVEPOINT can only be used in transaction blocks
  RELEASE SAVEPOINT one;
! ERROR:  RELEASE SAVEPOINT can only be used in transaction blocks
  -- Only "rollback to" allowed in aborted state
  BEGIN;
    SAVEPOINT one;
--- 363,373 ----
  DROP TABLE savepoints;
  -- only in a transaction block:
  SAVEPOINT one;
! WARNING:  SAVEPOINT can only be used in transaction blocks
  ROLLBACK TO SAVEPOINT one;
! WARNING:  ROLLBACK TO SAVEPOINT can only be used in transaction blocks
  RELEASE SAVEPOINT one;
! WARNING:  RELEASE SAVEPOINT can only be used in transaction blocks
  -- Only "rollback to" allowed in aborted state
  BEGIN;
    SAVEPOINT one;
