mysql/conn/
transaction.rs1use mysql_common::packets::OkPacket;
10
11use std::{borrow::Cow, fmt};
12
13use crate::{
14 conn::{
15 query_result::{Binary, Text},
16 ConnMut,
17 },
18 prelude::*,
19 LocalInfileHandler, Params, QueryResult, Result, Statement,
20};
21
22#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
24pub struct TxOpts {
25 with_consistent_snapshot: bool,
26 isolation_level: Option<IsolationLevel>,
27 access_mode: Option<AccessMode>,
28}
29
30impl TxOpts {
31 pub fn with_consistent_snapshot(&self) -> bool {
33 self.with_consistent_snapshot
34 }
35
36 pub fn access_mode(&self) -> Option<AccessMode> {
38 self.access_mode
39 }
40
41 pub fn isolation_level(&self) -> Option<IsolationLevel> {
43 self.isolation_level
44 }
45
46 pub fn set_with_consistent_snapshot(mut self, val: bool) -> Self {
48 self.with_consistent_snapshot = val;
49 self
50 }
51
52 pub fn set_access_mode(mut self, access_mode: Option<AccessMode>) -> Self {
54 self.access_mode = access_mode;
55 self
56 }
57
58 pub fn set_isolation_level(mut self, level: Option<IsolationLevel>) -> Self {
60 self.isolation_level = level;
61 self
62 }
63}
64
65#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
67#[repr(u8)]
68pub enum AccessMode {
69 ReadOnly,
70 ReadWrite,
71}
72
73#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
75#[repr(u8)]
76pub enum IsolationLevel {
77 ReadUncommitted,
78 ReadCommitted,
79 RepeatableRead,
80 Serializable,
81}
82
83impl fmt::Display for IsolationLevel {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 match *self {
86 IsolationLevel::ReadUncommitted => write!(f, "READ UNCOMMITTED"),
87 IsolationLevel::ReadCommitted => write!(f, "READ COMMITTED"),
88 IsolationLevel::RepeatableRead => write!(f, "REPEATABLE READ"),
89 IsolationLevel::Serializable => write!(f, "SERIALIZABLE"),
90 }
91 }
92}
93
94#[derive(Debug)]
95pub struct Transaction<'a> {
96 pub(crate) conn: ConnMut<'a, 'static, 'static>,
97 committed: bool,
98 rolled_back: bool,
99 restore_local_infile_handler: Option<LocalInfileHandler>,
100}
101
102impl Transaction<'_> {
103 pub(crate) fn new<'a>(conn: ConnMut<'a, 'static, 'static>) -> Transaction<'a> {
104 let handler = conn.0.local_infile_handler.clone();
105 Transaction {
106 conn,
107 committed: false,
108 rolled_back: false,
109 restore_local_infile_handler: handler,
110 }
111 }
112
113 pub fn commit(mut self) -> Result<()> {
115 self.conn.query_drop("COMMIT")?;
116 self.committed = true;
117 Ok(())
118 }
119
120 pub fn rollback(mut self) -> Result<()> {
123 self.conn.query_drop("ROLLBACK")?;
124 self.rolled_back = true;
125 Ok(())
126 }
127
128 pub fn set_local_infile_handler(&mut self, handler: Option<LocalInfileHandler>) {
131 self.conn.set_local_infile_handler(handler);
132 }
133
134 pub fn affected_rows(&self) -> u64 {
136 self.conn.affected_rows()
137 }
138
139 pub fn last_insert_id(&self) -> Option<u64> {
141 self.conn
142 .0
143 .ok_packet
144 .as_ref()
145 .and_then(OkPacket::last_insert_id)
146 }
147
148 pub fn warnings(&self) -> u16 {
150 self.conn.warnings()
151 }
152
153 pub fn info_ref(&self) -> &[u8] {
159 self.conn.info_ref()
160 }
161
162 pub fn info_str(&self) -> Cow<str> {
168 self.conn.info_str()
169 }
170}
171
172impl<'a> Queryable for Transaction<'a> {
173 fn query_iter<T: AsRef<str>>(&mut self, query: T) -> Result<QueryResult<'_, '_, '_, Text>> {
174 self.conn.query_iter(query)
175 }
176
177 fn prep<T: AsRef<str>>(&mut self, query: T) -> Result<Statement> {
178 self.conn.prep(query)
179 }
180
181 fn close(&mut self, stmt: Statement) -> Result<()> {
182 self.conn.close(stmt)
183 }
184
185 fn exec_iter<S, P>(&mut self, stmt: S, params: P) -> Result<QueryResult<'_, '_, '_, Binary>>
186 where
187 S: AsStatement,
188 P: Into<Params>,
189 {
190 self.conn.exec_iter(stmt, params)
191 }
192}
193
194impl<'a> Drop for Transaction<'a> {
195 fn drop(&mut self) {
197 if !self.committed && !self.rolled_back {
198 let _ = self.conn.query_drop("ROLLBACK");
199 }
200 self.conn.0.local_infile_handler = self.restore_local_infile_handler.take();
201 }
202}