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