Skip to main content

qail_pg/driver/
transaction.rs

1//! Transaction control methods for PostgreSQL connection.
2
3use super::{PgConnection, PgResult};
4
5/// Quote a SQL identifier (for savepoint names).
6/// Wraps in double-quotes and escapes embedded double-quotes and NUL bytes.
7fn quote_savepoint_name(name: &str) -> String {
8    let clean = name.replace('\0', "").replace('"', "\"\"");
9    format!("\"{}\"", clean)
10}
11
12impl PgConnection {
13    /// Begin a new transaction.
14    /// After calling this, all queries run within the transaction
15    /// until `commit()` or `rollback()` is called.
16    pub async fn begin_transaction(&mut self) -> PgResult<()> {
17        self.execute_simple("BEGIN").await
18    }
19
20    /// Commit the current transaction.
21    /// Makes all changes since `begin_transaction()` permanent.
22    pub async fn commit(&mut self) -> PgResult<()> {
23        self.execute_simple("COMMIT").await
24    }
25
26    /// Rollback the current transaction.
27    /// Discards all changes since `begin_transaction()`.
28    pub async fn rollback(&mut self) -> PgResult<()> {
29        self.execute_simple("ROLLBACK").await
30    }
31
32    /// Create a named savepoint within the current transaction.
33    /// Savepoints allow partial rollback within a transaction.
34    /// Use `rollback_to()` to return to this savepoint.
35    pub async fn savepoint(&mut self, name: &str) -> PgResult<()> {
36        self.execute_simple(&format!("SAVEPOINT {}", quote_savepoint_name(name)))
37            .await
38    }
39
40    /// Rollback to a previously created savepoint.
41    /// Discards all changes since the named savepoint was created,
42    /// but keeps the transaction open.
43    pub async fn rollback_to(&mut self, name: &str) -> PgResult<()> {
44        self.execute_simple(&format!(
45            "ROLLBACK TO SAVEPOINT {}",
46            quote_savepoint_name(name)
47        ))
48        .await
49    }
50
51    /// Release a savepoint (free resources, if no longer needed).
52    pub async fn release_savepoint(&mut self, name: &str) -> PgResult<()> {
53        self.execute_simple(&format!("RELEASE SAVEPOINT {}", quote_savepoint_name(name)))
54            .await
55    }
56}