1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use backend::UsesAnsiSavepointSyntax;
use connection::{Connection, SimpleConnection};
use result::QueryResult;
pub trait TransactionManager<Conn: Connection> {
fn begin_transaction(&self, conn: &Conn) -> QueryResult<()>;
fn rollback_transaction(&self, conn: &Conn) -> QueryResult<()>;
fn commit_transaction(&self, conn: &Conn) -> QueryResult<()>;
fn get_transaction_depth(&self) -> u32;
}
use std::cell::Cell;
#[allow(missing_debug_implementations)]
#[derive(Default)]
pub struct AnsiTransactionManager {
transaction_depth: Cell<i32>,
}
impl AnsiTransactionManager {
pub fn new() -> Self {
AnsiTransactionManager::default()
}
fn change_transaction_depth(&self, by: i32, query: QueryResult<()>) -> QueryResult<()> {
if query.is_ok() {
self.transaction_depth
.set(self.transaction_depth.get() + by)
}
query
}
pub fn begin_transaction_sql<Conn>(&self, conn: &Conn, sql: &str) -> QueryResult<()>
where
Conn: SimpleConnection,
{
use result::Error::AlreadyInTransaction;
if self.transaction_depth.get() == 0 {
self.change_transaction_depth(1, conn.batch_execute(sql))
} else {
Err(AlreadyInTransaction)
}
}
}
impl<Conn> TransactionManager<Conn> for AnsiTransactionManager
where
Conn: Connection,
Conn::Backend: UsesAnsiSavepointSyntax,
{
fn begin_transaction(&self, conn: &Conn) -> QueryResult<()> {
let transaction_depth = self.transaction_depth.get();
self.change_transaction_depth(
1,
if transaction_depth == 0 {
conn.batch_execute("BEGIN")
} else {
conn.batch_execute(&format!("SAVEPOINT diesel_savepoint_{}", transaction_depth))
},
)
}
fn rollback_transaction(&self, conn: &Conn) -> QueryResult<()> {
let transaction_depth = self.transaction_depth.get();
self.change_transaction_depth(
-1,
if transaction_depth == 1 {
conn.batch_execute("ROLLBACK")
} else {
conn.batch_execute(&format!(
"ROLLBACK TO SAVEPOINT diesel_savepoint_{}",
transaction_depth - 1
))
},
)
}
fn commit_transaction(&self, conn: &Conn) -> QueryResult<()> {
let transaction_depth = self.transaction_depth.get();
self.change_transaction_depth(
-1,
if transaction_depth <= 1 {
conn.batch_execute("COMMIT")
} else {
conn.batch_execute(&format!(
"RELEASE SAVEPOINT diesel_savepoint_{}",
transaction_depth - 1
))
},
)
}
fn get_transaction_depth(&self) -> u32 {
self.transaction_depth.get() as u32
}
}