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))).await
37 }
38
39 /// Rollback to a previously created savepoint.
40 /// Discards all changes since the named savepoint was created,
41 /// but keeps the transaction open.
42 pub async fn rollback_to(&mut self, name: &str) -> PgResult<()> {
43 self.execute_simple(&format!("ROLLBACK TO SAVEPOINT {}", quote_savepoint_name(name)))
44 .await
45 }
46
47 /// Release a savepoint (free resources, if no longer needed).
48 pub async fn release_savepoint(&mut self, name: &str) -> PgResult<()> {
49 self.execute_simple(&format!("RELEASE SAVEPOINT {}", quote_savepoint_name(name)))
50 .await
51 }
52}