@@ -20015,3 +20015,86 @@ fn parse_function_arg_call_chain_no_exponential_blowup() {
2001520015 rx.recv_timeout(Duration::from_secs(5))
2001620016 .expect("parser should reject this quickly, not loop exponentially");
2001720017}
20018+
20019+ #[test]
20020+ fn parse_transaction_deferrable_mode() {
20021+ // The third transaction mode of the SQL standard, spelled the same in
20022+ // PostgreSQL: <https://www.postgresql.org/docs/current/sql-set-transaction.html>
20023+ let dialects = all_dialects_except(|d|
20024+ // BigQuery and Snowflake do not support this syntax
20025+ d.is::<BigQueryDialect>() || d.is::<SnowflakeDialect>());
20026+
20027+ match dialects.verified_stmt("START TRANSACTION DEFERRABLE") {
20028+ Statement::StartTransaction { modes, .. } => {
20029+ assert_eq!(modes, vec![TransactionMode::Deferrable(true)])
20030+ }
20031+ _ => unreachable!(),
20032+ }
20033+
20034+ dialects.verified_stmt("BEGIN TRANSACTION NOT DEFERRABLE");
20035+
20036+ // PostgreSQL's `BEGIN` needs no transaction keyword; MsSql reads a bare
20037+ // `BEGIN` followed by anything else as the start of a `BEGIN ... END` block.
20038+ all_dialects_except(|d| {
20039+ d.is::<BigQueryDialect>() || d.is::<SnowflakeDialect>() || d.is::<MsSqlDialect>()
20040+ })
20041+ .verified_stmt("BEGIN DEFERRABLE");
20042+
20043+ match dialects
20044+ .verified_stmt("START TRANSACTION ISOLATION LEVEL SERIALIZABLE, READ ONLY, DEFERRABLE")
20045+ {
20046+ Statement::StartTransaction { modes, .. } => assert_eq!(
20047+ modes,
20048+ vec![
20049+ TransactionMode::IsolationLevel(TransactionIsolationLevel::Serializable),
20050+ TransactionMode::AccessMode(TransactionAccessMode::ReadOnly),
20051+ TransactionMode::Deferrable(true),
20052+ ]
20053+ ),
20054+ _ => unreachable!(),
20055+ }
20056+
20057+ // As with the other modes, PostgreSQL allows the commas to be omitted.
20058+ match dialects.one_statement_parses_to(
20059+ "START TRANSACTION NOT DEFERRABLE READ WRITE",
20060+ "START TRANSACTION NOT DEFERRABLE, READ WRITE",
20061+ ) {
20062+ Statement::StartTransaction { modes, .. } => assert_eq!(
20063+ modes,
20064+ vec![
20065+ TransactionMode::Deferrable(false),
20066+ TransactionMode::AccessMode(TransactionAccessMode::ReadWrite),
20067+ ]
20068+ ),
20069+ _ => unreachable!(),
20070+ }
20071+
20072+ match verified_stmt("SET TRANSACTION DEFERRABLE") {
20073+ Statement::Set(Set::SetTransaction { modes, .. }) => {
20074+ assert_eq!(modes, vec![TransactionMode::Deferrable(true)])
20075+ }
20076+ _ => unreachable!(),
20077+ }
20078+
20079+ match verified_stmt("SET SESSION CHARACTERISTICS AS TRANSACTION NOT DEFERRABLE") {
20080+ Statement::Set(Set::SetTransaction { modes, session, .. }) => {
20081+ assert_eq!(modes, vec![TransactionMode::Deferrable(false)]);
20082+ assert!(session);
20083+ }
20084+ _ => unreachable!(),
20085+ }
20086+
20087+ assert_eq!(
20088+ ParserError::ParserError("Expected: DEFERRABLE, found: SERIALIZABLE".to_string()),
20089+ dialects
20090+ .parse_sql_statements("START TRANSACTION NOT SERIALIZABLE")
20091+ .unwrap_err()
20092+ );
20093+
20094+ assert_eq!(
20095+ ParserError::ParserError("Expected: transaction mode, found: EOF".to_string()),
20096+ dialects
20097+ .parse_sql_statements("START TRANSACTION DEFERRABLE,")
20098+ .unwrap_err()
20099+ );
20100+ }
0 commit comments