uqa_sql/semantics/effects/
transaction_blocks.rs1use crate::SQLError;
10
11pub fn transaction_requires_explicit_block(transaction: &crate::ast::TransactionStmt) -> bool {
12 matches!(
13 transaction,
14 crate::ast::TransactionStmt::Savepoint(_)
15 | crate::ast::TransactionStmt::ReleaseSavepoint(_)
16 | crate::ast::TransactionStmt::RollbackToSavepoint(_)
17 | crate::ast::TransactionStmt::CommitAndChain
18 | crate::ast::TransactionStmt::RollbackAndChain
19 )
20}
21
22pub fn no_active_transaction_error(transaction: &crate::ast::TransactionStmt) -> SQLError {
23 let command = match transaction {
24 crate::ast::TransactionStmt::Savepoint(_) => "SAVEPOINT",
25 crate::ast::TransactionStmt::ReleaseSavepoint(_) => "RELEASE SAVEPOINT",
26 crate::ast::TransactionStmt::RollbackToSavepoint(_) => "ROLLBACK TO SAVEPOINT",
27 crate::ast::TransactionStmt::CommitAndChain => "COMMIT AND CHAIN",
28 crate::ast::TransactionStmt::RollbackAndChain => "ROLLBACK AND CHAIN",
29 _ => unreachable!("only explicit-block transaction commands use this error"),
30 };
31 SQLError::Routine {
32 sqlstate: "25P01".into(),
33 message: format!("{command} can only be used in transaction blocks"),
34 }
35}
36
37#[cfg(test)]
38mod tests {
39 use super::{no_active_transaction_error, transaction_requires_explicit_block};
40 use crate::{ast::TransactionStmt, SQLError};
41
42 #[test]
43 fn explicit_block_commands_keep_their_individual_diagnostics() {
44 for (command, spelling) in [
45 (TransactionStmt::Savepoint("s".into()), "SAVEPOINT"),
46 (
47 TransactionStmt::ReleaseSavepoint("s".into()),
48 "RELEASE SAVEPOINT",
49 ),
50 (
51 TransactionStmt::RollbackToSavepoint("s".into()),
52 "ROLLBACK TO SAVEPOINT",
53 ),
54 (TransactionStmt::CommitAndChain, "COMMIT AND CHAIN"),
55 (TransactionStmt::RollbackAndChain, "ROLLBACK AND CHAIN"),
56 ] {
57 assert!(transaction_requires_explicit_block(&command));
58 assert!(
59 matches!(no_active_transaction_error(&command), SQLError::Routine { sqlstate, message } if sqlstate == "25P01" && message == format!("{spelling} can only be used in transaction blocks"))
60 );
61 }
62 for command in [
63 TransactionStmt::Begin,
64 TransactionStmt::Commit,
65 TransactionStmt::Rollback,
66 ] {
67 assert!(!transaction_requires_explicit_block(&command));
68 }
69 }
70}