Commit a6542a4b authored by Bruce Momjian's avatar Bruce Momjian

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.
parent 05b476c2
...@@ -63,8 +63,7 @@ ABORT [ WORK | TRANSACTION ] ...@@ -63,8 +63,7 @@ ABORT [ WORK | TRANSACTION ]
</para> </para>
<para> <para>
Issuing <command>ABORT</> when not inside a transaction does Issuing <command>ABORT</> outside of a transaction block has no effect.
no harm, but it will provoke a warning message.
</para> </para>
</refsect1> </refsect1>
......
...@@ -59,8 +59,8 @@ ROLLBACK [ WORK | TRANSACTION ] ...@@ -59,8 +59,8 @@ ROLLBACK [ WORK | TRANSACTION ]
</para> </para>
<para> <para>
Issuing <command>ROLLBACK</> when not inside a transaction does Issuing <command>ROLLBACK</> outside of a transaction
no harm, but it will provoke a warning message. block has no effect.
</para> </para>
</refsect1> </refsect1>
......
...@@ -110,9 +110,8 @@ SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="PARAMETER">timezone</rep ...@@ -110,9 +110,8 @@ SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="PARAMETER">timezone</rep
<para> <para>
Specifies that the command takes effect for only the current Specifies that the command takes effect for only the current
transaction. After <command>COMMIT</> or <command>ROLLBACK</>, transaction. After <command>COMMIT</> or <command>ROLLBACK</>,
the session-level setting takes effect again. the session-level setting takes effect again. This has no effect
<productname>PostgreSQL</productname> reports an error if outside of a transaction block.
<command>SET LOCAL</> is used outside a transaction block.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
......
...@@ -99,10 +99,7 @@ SET CONSTRAINTS { ALL | <replaceable class="parameter">name</replaceable> [, ... ...@@ -99,10 +99,7 @@ SET CONSTRAINTS { ALL | <replaceable class="parameter">name</replaceable> [, ...
<para> <para>
This command only alters the behavior of constraints within the This command only alters the behavior of constraints within the
current transaction. Thus, if you execute this command outside of a current transaction. This has no effect outside of a transaction block.
transaction block
(<command>BEGIN</command>/<command>COMMIT</command> pair), it will
generate an error.
</para> </para>
</refsect1> </refsect1>
......
...@@ -185,7 +185,7 @@ SET SESSION CHARACTERISTICS AS TRANSACTION <replaceable class="parameter">transa ...@@ -185,7 +185,7 @@ SET SESSION CHARACTERISTICS AS TRANSACTION <replaceable class="parameter">transa
<para> <para>
If <command>SET TRANSACTION</command> is executed without a prior If <command>SET TRANSACTION</command> is executed without a prior
<command>START TRANSACTION</command> or <command>BEGIN</command>, <command>START TRANSACTION</command> or <command>BEGIN</command>,
it will generate an error. it will have no effect.
</para> </para>
<para> <para>
......
...@@ -265,6 +265,8 @@ static void CallSubXactCallbacks(SubXactEvent event, ...@@ -265,6 +265,8 @@ static void CallSubXactCallbacks(SubXactEvent event,
SubTransactionId mySubid, SubTransactionId mySubid,
SubTransactionId parentSubid); SubTransactionId parentSubid);
static void CleanupTransaction(void); static void CleanupTransaction(void);
static void CheckTransactionChain(bool isTopLevel, bool throwError,
const char *stmtType);
static void CommitTransaction(void); static void CommitTransaction(void);
static TransactionId RecordTransactionAbort(bool isSubXact); static TransactionId RecordTransactionAbort(bool isSubXact);
static void StartTransaction(void); static void StartTransaction(void);
...@@ -2948,6 +2950,26 @@ PreventTransactionChain(bool isTopLevel, const char *stmtType) ...@@ -2948,6 +2950,26 @@ PreventTransactionChain(bool isTopLevel, const char *stmtType)
/* all okay */ /* 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 * RequireTransactionChain
* *
...@@ -2957,16 +2979,16 @@ PreventTransactionChain(bool isTopLevel, const char *stmtType) ...@@ -2957,16 +2979,16 @@ PreventTransactionChain(bool isTopLevel, const char *stmtType)
* is presumably an error). DECLARE CURSOR is an example. * is presumably an error). DECLARE CURSOR is an example.
* *
* If we appear to be running inside a user-defined function, we do not * 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. * use of the current statement's results. Likewise subtransactions.
* Thus this is an inverse for PreventTransactionChain. * Thus this is an inverse for PreventTransactionChain.
* *
* isTopLevel: passed down from ProcessUtility to determine whether we are * isTopLevel: passed down from ProcessUtility to determine whether we are
* inside a function. * inside a function.
* stmtType: statement type name, for error messages. * stmtType: statement type name, for warning or error messages.
*/ */
void static void
RequireTransactionChain(bool isTopLevel, const char *stmtType) CheckTransactionChain(bool isTopLevel, bool throwError, const char *stmtType)
{ {
/* /*
* xact block already started? * xact block already started?
...@@ -2986,11 +3008,12 @@ RequireTransactionChain(bool isTopLevel, const char *stmtType) ...@@ -2986,11 +3008,12 @@ RequireTransactionChain(bool isTopLevel, const char *stmtType)
if (!isTopLevel) if (!isTopLevel)
return; return;
ereport(ERROR, ereport(throwError ? ERROR : WARNING,
(errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION), (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
/* translator: %s represents an SQL statement name */ /* translator: %s represents an SQL statement name */
errmsg("%s can only be used in transaction blocks", errmsg("%s can only be used in transaction blocks",
stmtType))); stmtType)));
return;
} }
/* /*
...@@ -3425,12 +3448,12 @@ UserAbortTransactionBlock(void) ...@@ -3425,12 +3448,12 @@ UserAbortTransactionBlock(void)
/* /*
* The user issued ABORT when not inside a transaction. Issue a * 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 * CommitTransactionCommand() will then put us back into the
* default state. * default state.
*/ */
case TBLOCK_STARTED: case TBLOCK_STARTED:
ereport(NOTICE, ereport(WARNING,
(errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION), (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
errmsg("there is no transaction in progress"))); errmsg("there is no transaction in progress")));
s->blockState = TBLOCK_ABORT_PENDING; s->blockState = TBLOCK_ABORT_PENDING;
......
...@@ -754,7 +754,7 @@ standard_ProcessUtility(Node *parsetree, ...@@ -754,7 +754,7 @@ standard_ProcessUtility(Node *parsetree,
break; break;
case T_ConstraintsSetStmt: case T_ConstraintsSetStmt:
RequireTransactionChain(isTopLevel, "SET CONSTRAINTS"); WarnNoTransactionChain(isTopLevel, "SET CONSTRAINTS");
AfterTriggerSetState((ConstraintsSetStmt *) parsetree); AfterTriggerSetState((ConstraintsSetStmt *) parsetree);
break; break;
......
...@@ -6274,7 +6274,7 @@ ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel) ...@@ -6274,7 +6274,7 @@ ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel)
case VAR_SET_VALUE: case VAR_SET_VALUE:
case VAR_SET_CURRENT: case VAR_SET_CURRENT:
if (stmt->is_local) if (stmt->is_local)
RequireTransactionChain(isTopLevel, "SET LOCAL"); WarnNoTransactionChain(isTopLevel, "SET LOCAL");
(void) set_config_option(stmt->name, (void) set_config_option(stmt->name,
ExtractSetVariableArgs(stmt), ExtractSetVariableArgs(stmt),
(superuser() ? PGC_SUSET : PGC_USERSET), (superuser() ? PGC_SUSET : PGC_USERSET),
...@@ -6295,7 +6295,7 @@ ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel) ...@@ -6295,7 +6295,7 @@ ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel)
{ {
ListCell *head; ListCell *head;
RequireTransactionChain(isTopLevel, "SET TRANSACTION"); WarnNoTransactionChain(isTopLevel, "SET TRANSACTION");
foreach(head, stmt->args) foreach(head, stmt->args)
{ {
...@@ -6346,7 +6346,7 @@ ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel) ...@@ -6346,7 +6346,7 @@ ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel)
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("SET LOCAL TRANSACTION SNAPSHOT is not implemented"))); errmsg("SET LOCAL TRANSACTION SNAPSHOT is not implemented")));
RequireTransactionChain(isTopLevel, "SET TRANSACTION"); WarnNoTransactionChain(isTopLevel, "SET TRANSACTION");
Assert(IsA(con, A_Const)); Assert(IsA(con, A_Const));
Assert(nodeTag(&con->val) == T_String); Assert(nodeTag(&con->val) == T_String);
ImportSnapshot(strVal(&con->val)); ImportSnapshot(strVal(&con->val));
...@@ -6357,11 +6357,11 @@ ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel) ...@@ -6357,11 +6357,11 @@ ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel)
break; break;
case VAR_SET_DEFAULT: case VAR_SET_DEFAULT:
if (stmt->is_local) if (stmt->is_local)
RequireTransactionChain(isTopLevel, "SET LOCAL"); WarnNoTransactionChain(isTopLevel, "SET LOCAL");
/* fall through */ /* fall through */
case VAR_RESET: case VAR_RESET:
if (strcmp(stmt->name, "transaction_isolation") == 0) if (strcmp(stmt->name, "transaction_isolation") == 0)
RequireTransactionChain(isTopLevel, "RESET TRANSACTION"); WarnNoTransactionChain(isTopLevel, "RESET TRANSACTION");
(void) set_config_option(stmt->name, (void) set_config_option(stmt->name,
NULL, NULL,
......
...@@ -245,6 +245,7 @@ extern char TransactionBlockStatusCode(void); ...@@ -245,6 +245,7 @@ extern char TransactionBlockStatusCode(void);
extern void AbortOutOfAnyTransaction(void); extern void AbortOutOfAnyTransaction(void);
extern void PreventTransactionChain(bool isTopLevel, const char *stmtType); extern void PreventTransactionChain(bool isTopLevel, const char *stmtType);
extern void RequireTransactionChain(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 bool IsInTransactionChain(bool isTopLevel);
extern void RegisterXactCallback(XactCallback callback, void *arg); extern void RegisterXactCallback(XactCallback callback, void *arg);
extern void UnregisterXactCallback(XactCallback callback, void *arg); extern void UnregisterXactCallback(XactCallback callback, void *arg);
......
...@@ -114,7 +114,7 @@ ERROR: column name "oid" conflicts with a system column name ...@@ -114,7 +114,7 @@ ERROR: column name "oid" conflicts with a system column name
-- TRANSACTION STUFF -- TRANSACTION STUFF
-- not in a xact -- not in a xact
abort; abort;
NOTICE: there is no transaction in progress WARNING: there is no transaction in progress
-- not in a xact -- not in a xact
end; end;
WARNING: there is no transaction in progress WARNING: there is no transaction in progress
......
...@@ -29,7 +29,7 @@ SELECT '2006-08-13 12:34:56'::timestamptz; ...@@ -29,7 +29,7 @@ SELECT '2006-08-13 12:34:56'::timestamptz;
-- SET LOCAL has no effect outside of a transaction -- SET LOCAL has no effect outside of a transaction
SET LOCAL vacuum_cost_delay TO 50; 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; SHOW vacuum_cost_delay;
vacuum_cost_delay vacuum_cost_delay
------------------- -------------------
...@@ -37,7 +37,7 @@ SHOW vacuum_cost_delay; ...@@ -37,7 +37,7 @@ SHOW vacuum_cost_delay;
(1 row) (1 row)
SET LOCAL datestyle = 'SQL'; 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; SHOW datestyle;
DateStyle DateStyle
----------- -----------
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment