On Thu, Sep 12, 2013 at 09:38:43AM +0530, Amit Kapila wrote:
> > I have created the attached patch which issues an error when SET
> > TRANSACTION and SET LOCAL are used outside of transactions:
> >
> > test=> set transaction isolation level serializable;
> > ERROR: SET TRANSACTION can only be used in transaction blocks
> > test=> reset transaction isolation level;
> > ERROR: RESET TRANSACTION can only be used in transaction blocks
> >
> > test=> set local effective_cache_size = '3MB';
> > ERROR: SET LOCAL can only be used in transaction blocks
> > test=> set local effective_cache_size = default;
> > ERROR: SET LOCAL can only be used in transaction blocks
>
> Shouldn't we do it for Set Constraints as well?
Oh, very good point. I missed that one. Updated patch attached.
--
Bruce Momjian <[email protected]> http://momjian.us
EnterpriseDB http://enterprisedb.com
+ It's impossible for everything to be true. +
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
new file mode 100644
index b1023c4..3ffdfe0
*** a/src/backend/tcop/utility.c
--- b/src/backend/tcop/utility.c
*************** standard_ProcessUtility(Node *parsetree,
*** 688,694 ****
break;
case T_VariableSetStmt:
! ExecSetVariableStmt((VariableSetStmt *) parsetree);
break;
case T_VariableShowStmt:
--- 688,694 ----
break;
case T_VariableSetStmt:
! ExecSetVariableStmt((VariableSetStmt *) parsetree, isTopLevel);
break;
case T_VariableShowStmt:
*************** standard_ProcessUtility(Node *parsetree,
*** 754,759 ****
--- 754,760 ----
break;
case T_ConstraintsSetStmt:
+ RequireTransactionChain(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 3107f9c..ff39920
*** a/src/backend/utils/misc/guc.c
--- b/src/backend/utils/misc/guc.c
*************** flatten_set_variable_args(const char *na
*** 6252,6258 ****
* SET command
*/
void
! ExecSetVariableStmt(VariableSetStmt *stmt)
{
GucAction action = stmt->is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET;
--- 6252,6258 ----
* SET command
*/
void
! ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel)
{
GucAction action = stmt->is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET;
*************** ExecSetVariableStmt(VariableSetStmt *stm
*** 6260,6265 ****
--- 6260,6267 ----
{
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),
*************** ExecSetVariableStmt(VariableSetStmt *stm
*** 6269,6275 ****
0);
break;
case VAR_SET_MULTI:
-
/*
* Special-case SQL syntaxes. The TRANSACTION and SESSION
* CHARACTERISTICS cases effectively set more than one variable
--- 6271,6276 ----
*************** ExecSetVariableStmt(VariableSetStmt *stm
*** 6281,6286 ****
--- 6282,6289 ----
{
ListCell *head;
+ RequireTransactionChain(isTopLevel, "SET TRANSACTION");
+
foreach(head, stmt->args)
{
DefElem *item = (DefElem *) lfirst(head);
*************** ExecSetVariableStmt(VariableSetStmt *stm
*** 6325,6330 ****
--- 6328,6335 ----
{
A_Const *con = (A_Const *) linitial(stmt->args);
+ RequireTransactionChain(isTopLevel, "SET TRANSACTION");
+
if (stmt->is_local)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
*************** ExecSetVariableStmt(VariableSetStmt *stm
*** 6338,6344 ****
--- 6343,6355 ----
stmt->name);
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,
(superuser() ? PGC_SUSET : PGC_USERSET),
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
new file mode 100644
index 99211c1..89ee40c
*** a/src/include/utils/guc.h
--- b/src/include/utils/guc.h
*************** extern void SetPGVariable(const char *na
*** 334,340 ****
extern void GetPGVariable(const char *name, DestReceiver *dest);
extern TupleDesc GetPGVariableResultDesc(const char *name);
! extern void ExecSetVariableStmt(VariableSetStmt *stmt);
extern char *ExtractSetVariableArgs(VariableSetStmt *stmt);
extern void ProcessGUCArray(ArrayType *array,
--- 334,340 ----
extern void GetPGVariable(const char *name, DestReceiver *dest);
extern TupleDesc GetPGVariableResultDesc(const char *name);
! extern void ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel);
extern char *ExtractSetVariableArgs(VariableSetStmt *stmt);
extern void ProcessGUCArray(ArrayType *array,
diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out
new file mode 100644
index 7b5a624..203fa6e
*** a/src/test/regress/expected/guc.out
--- b/src/test/regress/expected/guc.out
*************** SELECT '2006-08-13 12:34:56'::timestampt
*** 29,34 ****
--- 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
-------------------
*************** SHOW vacuum_cost_delay;
*** 36,41 ****
--- 37,43 ----
(1 row)
SET LOCAL datestyle = 'SQL';
+ ERROR: SET LOCAL can only be used in transaction blocks
SHOW datestyle;
DateStyle
-----------
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers