vibesql_executor/
transaction.rs

1//! Transaction control statement execution (BEGIN, COMMIT, ROLLBACK)
2
3use vibesql_ast::{
4    BeginStmt, CommitStmt, DurabilityHint, ReleaseSavepointStmt, RollbackStmt,
5    RollbackToSavepointStmt, SavepointStmt,
6};
7use vibesql_storage::{Database, TransactionDurability};
8
9use crate::errors::ExecutorError;
10
11/// Convert AST DurabilityHint to storage TransactionDurability
12fn convert_durability_hint(hint: &DurabilityHint) -> TransactionDurability {
13    match hint {
14        DurabilityHint::Default => TransactionDurability::Default,
15        DurabilityHint::Durable => TransactionDurability::ForceDurable,
16        DurabilityHint::Lazy => TransactionDurability::AllowLazy,
17        DurabilityHint::Volatile => TransactionDurability::ForceVolatile,
18    }
19}
20
21/// Executor for BEGIN TRANSACTION statements
22pub struct BeginTransactionExecutor;
23
24impl BeginTransactionExecutor {
25    /// Execute a BEGIN TRANSACTION statement
26    pub fn execute(stmt: &BeginStmt, db: &mut Database) -> Result<String, ExecutorError> {
27        let durability = convert_durability_hint(&stmt.durability);
28        db.begin_transaction_with_durability(durability).map_err(|e| {
29            ExecutorError::StorageError(format!("Failed to begin transaction: {}", e))
30        })?;
31
32        let msg = match stmt.durability {
33            DurabilityHint::Default => "Transaction started".to_string(),
34            DurabilityHint::Durable => "Transaction started (durability: DURABLE)".to_string(),
35            DurabilityHint::Lazy => "Transaction started (durability: LAZY)".to_string(),
36            DurabilityHint::Volatile => "Transaction started (durability: VOLATILE)".to_string(),
37        };
38        Ok(msg)
39    }
40}
41
42/// Executor for COMMIT statements
43pub struct CommitExecutor;
44
45impl CommitExecutor {
46    /// Execute a COMMIT statement
47    pub fn execute(_stmt: &CommitStmt, db: &mut Database) -> Result<String, ExecutorError> {
48        db.commit_transaction().map_err(|e| {
49            ExecutorError::StorageError(format!("Failed to commit transaction: {}", e))
50        })?;
51
52        Ok("Transaction committed".to_string())
53    }
54}
55
56/// Executor for ROLLBACK statements
57pub struct RollbackExecutor;
58
59impl RollbackExecutor {
60    /// Execute a ROLLBACK statement
61    pub fn execute(_stmt: &RollbackStmt, db: &mut Database) -> Result<String, ExecutorError> {
62        db.rollback_transaction().map_err(|e| {
63            ExecutorError::StorageError(format!("Failed to rollback transaction: {}", e))
64        })?;
65
66        Ok("Transaction rolled back".to_string())
67    }
68}
69
70/// Executor for SAVEPOINT statements
71pub struct SavepointExecutor;
72
73impl SavepointExecutor {
74    /// Execute a SAVEPOINT statement
75    pub fn execute(stmt: &SavepointStmt, db: &mut Database) -> Result<String, ExecutorError> {
76        db.create_savepoint(stmt.name.clone()).map_err(|e| {
77            ExecutorError::StorageError(format!("Failed to create savepoint: {}", e))
78        })?;
79
80        Ok(format!("Savepoint '{}' created", stmt.name))
81    }
82}
83
84/// Executor for ROLLBACK TO SAVEPOINT statements
85pub struct RollbackToSavepointExecutor;
86
87impl RollbackToSavepointExecutor {
88    /// Execute a ROLLBACK TO SAVEPOINT statement
89    pub fn execute(
90        stmt: &RollbackToSavepointStmt,
91        db: &mut Database,
92    ) -> Result<String, ExecutorError> {
93        db.rollback_to_savepoint(stmt.name.clone()).map_err(|e| {
94            ExecutorError::StorageError(format!("Failed to rollback to savepoint: {}", e))
95        })?;
96
97        Ok(format!("Rolled back to savepoint '{}'", stmt.name))
98    }
99}
100
101/// Executor for RELEASE SAVEPOINT statements
102pub struct ReleaseSavepointExecutor;
103
104impl ReleaseSavepointExecutor {
105    /// Execute a RELEASE SAVEPOINT statement
106    pub fn execute(
107        stmt: &ReleaseSavepointStmt,
108        db: &mut Database,
109    ) -> Result<String, ExecutorError> {
110        db.release_savepoint(stmt.name.clone()).map_err(|e| {
111            ExecutorError::StorageError(format!("Failed to release savepoint: {}", e))
112        })?;
113
114        Ok(format!("Savepoint '{}' released", stmt.name))
115    }
116}