Hi,
This is regarding the TODO item:
"Prevent the specification of conflicting transaction read/write options"
listed at:
http://wiki.postgresql.org/wiki/Todo
The issue is :
SET TRANSACTION read only read write read only;
The fix involved iteration over transaction_mode_list and checking for
duplicate entries.
The patch is based on suggestions mentioned in message:
http://archives.postgresql.org/pgsql-hackers/2009-01/msg00692.php
As per this, the patch does not throw any error for the first test case
mentioned above.
It throws error only in case of conflicting modes.
For ex:
postgres=# SET TRANSACTION read only read only;
SET
postgres=# SET TRANSACTION read only read write;
ERROR: conflicting options
LINE 1: SET TRANSACTION read only read write;
^
Below are basic unit test logs:
postgres=# SET TRANSACTION ISOLATION LEVEL serializable ISOLATION LEVEL
serializable;
SET
postgres=# SET TRANSACTION ISOLATION LEVEL serializable ISOLATION LEVEL
repeatable read;
ERROR: conflicting options
LINE 1: SET TRANSACTION ISOLATION LEVEL serializable ISOLATION LEVEL...
postgres=# SET TRANSACTION DEFERRABLE DEFERRABLE;
SET
postgres=# SET TRANSACTION DEFERRABLE NOT DEFERRABLE;
ERROR: conflicting options
LINE 1: SET TRANSACTION DEFERRABLE NOT DEFERRABLE;
^
postgres=# START TRANSACTION read only, read only;
START TRANSACTION
postgres=# rollback;
ROLLBACK
postgres=# START TRANSACTION read only, read write;
ERROR: conflicting options
LINE 1: START TRANSACTION read only, read write;
postgres=# rollback;
ROLLBACK ^
postgres=# BEGIN TRANSACTION ISOLATION LEVEL serializable, ISOLATION LEVEL
serializable;
BEGIN
postgres=# rollback;
ROLLBACK
postgres=# BEGIN TRANSACTION ISOLATION LEVEL serializable, ISOLATION LEVEL
repeatable read;
ERROR: conflicting options
LINE 1: BEGIN TRANSACTION ISOLATION LEVEL serializable, ISOLATION LE...
^
Please pass on any inputs on the patch.
Regards,
Chetan
--
EnterpriseDB Corporation
The Enterprise PostgreSQL Company
Website: www.enterprisedb.com
EnterpriseDB Blog : http://blogs.enterprisedb.com
Follow us on Twitter : http://www.twitter.com/enterprisedb
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 62fde67..28c987f 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -146,6 +146,9 @@ static void processCASbits(int cas_bits, int location, const char *constrType,
bool *deferrable, bool *initdeferred, bool *not_valid,
core_yyscan_t yyscanner);
+static void
+check_trans_mode(List *list, DefElem *elem, core_yyscan_t yyscanner);
+
%}
%pure-parser
@@ -7510,9 +7513,16 @@ transaction_mode_list:
transaction_mode_item
{ $$ = list_make1($1); }
| transaction_mode_list ',' transaction_mode_item
- { $$ = lappend($1, $3); }
+ {
+ check_trans_mode((List *)$1, (DefElem *)$3, yyscanner);
+ $$ = lappend($1, $3);
+ }
+
| transaction_mode_list transaction_mode_item
- { $$ = lappend($1, $2); }
+ {
+ check_trans_mode((List *)$1, (DefElem *)$2, yyscanner);
+ $$ = lappend($1, $2);
+ }
;
transaction_mode_list_or_empty:
@@ -13215,6 +13225,57 @@ parser_init(base_yy_extra_type *yyext)
}
/*
+ * checks for conflicting transaction modes by looking up current
+ * element in the given list.
+ */
+static void
+check_trans_mode(List *list, DefElem *elem, core_yyscan_t yyscanner)
+{
+ ListCell *lc;
+ A_Const *elem_arg;
+
+ elem_arg =(A_Const *) elem->arg;
+
+ /* cannot specify conflicting value for transaction mode. */
+ foreach (lc, list)
+ {
+ DefElem *next;
+ A_Const *arg;
+
+ next = (DefElem*)lfirst (lc);
+ arg = (A_Const *)next->arg;
+
+ /* check for duplicate value in remaining list */
+ if (strcmp(elem->defname, next->defname) == 0)
+ {
+ /*
+ * isolation level values are stored
+ * as string whereas other modes are
+ * stored as integer values.
+ */
+ if (strcmp(elem->defname,"transaction_isolation") == 0)
+ {
+/* check for conflicting values */
+if (strcmp(elem_arg->val.val.str,arg->val.val.str)!= 0)
+ ereport(ERROR,
+(errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting options"),
+ parser_errposition(arg->location)));
+ }
+ else
+ {
+/* check for conflicting values */
+if (elem_arg->val.val.ival != arg->val.val.ival)
+ ereport(ERROR,
+(errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting options"),
+ parser_errposition(arg->location)));
+ }
+ }
+ }
+}
+
+/*
* Must undefine this stuff before including scan.c, since it has different
* definitions for these macros.
*/
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers