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}