diff --git a/Cargo.toml b/Cargo.toml index f3e68f6bc4..45de42bc4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ [package] name = "sqlparser-dsql" description = "SQL parser fork with Aurora DSQL extensions and DSQL-supported PostgreSQL syntax. Based on sqlparser 0.62.0." -version = "0.62.10" +version = "0.62.11" authors = [ "Apache DataFusion ", "Amazon Web Services", diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 96b74df924..ed08e4caec 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -15596,9 +15596,16 @@ impl<'a> Parser<'a> { } .into()); } else if self.parse_keyword(Keyword::CHARACTERISTICS) { + if scope != Some(ContextModifier::Session) { + return self.expected_ref("SESSION before CHARACTERISTICS", self.peek_token_ref()); + } self.expect_keywords(&[Keyword::AS, Keyword::TRANSACTION])?; + let modes = self.parse_transaction_modes()?; + if modes.is_empty() { + return self.expected_ref("a transaction mode", self.peek_token_ref()); + } return Ok(Set::SetTransaction { - modes: self.parse_transaction_modes()?, + modes, snapshot: None, session: true, } diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index 0812466bca..f7db11a504 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -9687,3 +9687,47 @@ fn dsql_aws_iam_custom_dialect_opt_in() { assert!(matches!(statements[0], Statement::AwsIamGrant { .. })); assert_eq!(statements[0].to_string(), sql); } + +#[test] +fn set_characteristics_requires_session_scope() { + for sql in [ + "SET CHARACTERISTICS AS TRANSACTION READ ONLY", + "SET CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL REPEATABLE READ", + "SET LOCAL CHARACTERISTICS AS TRANSACTION READ ONLY", + "SET LOCAL CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE", + "SET GLOBAL CHARACTERISTICS AS TRANSACTION READ WRITE", + "SET GLOBAL CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE", + ] { + assert!(pg_and_generic().parse_sql_statements(sql).is_err(), "{sql}"); + } +} + +#[test] +fn set_session_characteristics_preserves_transaction_modes() { + let sql = + "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL REPEATABLE READ, READ ONLY"; + let Statement::Set(Set::SetTransaction { + modes, + snapshot, + session, + }) = pg_and_generic().verified_stmt(sql) + else { + panic!("expected session transaction characteristics"); + }; + assert!(session); + assert!(snapshot.is_none()); + assert_eq!( + modes, + vec![ + TransactionMode::IsolationLevel(TransactionIsolationLevel::RepeatableRead), + TransactionMode::AccessMode(TransactionAccessMode::ReadOnly), + ] + ); +} + +#[test] +fn set_session_characteristics_requires_transaction_mode() { + assert!(pg_and_generic() + .parse_sql_statements("SET SESSION CHARACTERISTICS AS TRANSACTION") + .is_err()); +}