sqlite_bindings_lunatic/
connection.rs1use ffi;
2use libc::{c_char, c_int, c_void};
3use std::marker::PhantomData;
4use std::ops::{Deref, DerefMut};
5use std::path::Path;
6
7use error::Result;
8use statement::Statement;
9
10use crate::Error;
11
12pub struct Connection {
14 raw: Raw,
15 busy_callback: Option<Box<dyn FnMut(usize) -> bool + Send>>,
16 phantom: PhantomData<ffi::sqlite3>,
17}
18
19pub struct ConnectionWithFullMutex(Connection);
21
22#[derive(Clone, Copy, Debug)]
24pub struct OpenFlags(c_int);
25
26struct Raw(*mut ffi::sqlite3);
27
28impl Connection {
29 pub fn open<T: AsRef<Path>>(path: T) -> Result<Connection> {
31 Connection::open_with_flags(path, OpenFlags::new().set_create().set_read_write())
32 }
33
34 pub fn open_with_flags<T: AsRef<Path>>(path: T, flags: OpenFlags) -> Result<Connection> {
36 let mut raw = 0 as *mut _;
37 unsafe {
38 let code = ffi::sqlite3_open_v2(
39 path_to_cstr!(path.as_ref()).as_ptr(),
40 &mut raw,
41 flags.0,
42 0 as *const _,
43 );
44 match code {
45 ffi::SQLITE_OK => {}
46 code => match ::error::last(raw) {
47 Some(error) => {
48 ffi::sqlite3_close(raw);
49 return Err(error);
50 }
51 _ => {
52 ffi::sqlite3_close(raw);
53 return Err(::Error {
54 code: Some(code as isize),
55 message: None,
56 });
57 }
58 },
59 }
60 }
61 Ok(Connection {
62 raw: Raw(raw),
63 busy_callback: None,
64 phantom: PhantomData,
65 })
66 }
67
68 pub fn open_with_full_mutex<T: AsRef<Path>>(path: T) -> Result<ConnectionWithFullMutex> {
70 Connection::open_with_flags(
71 path,
72 OpenFlags::new()
73 .set_create()
74 .set_read_write()
75 .set_full_mutex(),
76 )
77 .map(ConnectionWithFullMutex)
78 }
79
80 #[inline]
82 pub fn execute<T: AsRef<str>>(&self, statement: T) -> Result<()> {
83 unsafe {
84 ok!(
85 self.raw.0,
86 ffi::sqlite3_exec(
87 self.raw.0,
88 str_to_cstr!(statement.as_ref()).as_ptr(),
89 None,
90 0 as *mut _,
91 0 as *mut _,
92 )
93 );
94 }
95 Ok(())
96 }
97
98 #[inline]
104 pub fn iterate<T: AsRef<str>, F>(&self, statement: T, callback: F) -> Result<()>
105 where
106 F: FnMut(&[(&str, Option<&str>)]) -> bool,
107 {
108 unsafe {
109 let callback = Box::new(callback);
110 ok!(
111 self.raw.0,
112 ffi::sqlite3_exec(
113 self.raw.0,
114 str_to_cstr!(statement.as_ref()).as_ptr(),
115 Some(process_callback::<F>),
116 &*callback as *const F as *mut F as *mut _,
117 0 as *mut _,
118 )
119 );
120 }
121 Ok(())
122 }
123
124 #[inline]
126 pub fn prepare<'l, T: AsRef<str>>(&'l self, statement: T) -> Result<Statement> {
127 ::statement::new(self.raw.0, statement)
128 }
129
130 #[inline]
133 pub fn change_count(&self) -> usize {
134 unsafe { ffi::sqlite3_changes(self.raw.0) as usize }
135 }
136
137 #[inline]
140 pub fn total_change_count(&self) -> usize {
141 unsafe { ffi::sqlite3_total_changes(self.raw.0) as usize }
142 }
143
144 pub fn set_busy_handler<F>(&mut self, callback: F) -> Result<()>
150 where
151 F: FnMut(usize) -> bool + Send + 'static,
152 {
153 self.remove_busy_handler()?;
154 unsafe {
155 let callback = Box::new(callback);
156 let result = ffi::sqlite3_busy_handler(
157 self.raw.0,
158 Some(busy_callback::<F>),
159 &*callback as *const F as *mut F as *mut _,
160 );
161 self.busy_callback = Some(callback);
162 ok!(self.raw.0, result);
163 }
164 Ok(())
165 }
166
167 #[inline]
170 pub fn set_busy_timeout(&mut self, milliseconds: usize) -> Result<()> {
171 unsafe {
172 ok!(
173 self.raw.0,
174 ffi::sqlite3_busy_timeout(self.raw.0, milliseconds as c_int)
175 );
176 }
177 Ok(())
178 }
179
180 #[inline]
182 pub fn remove_busy_handler(&mut self) -> Result<()> {
183 self.busy_callback = None;
184 unsafe {
185 ok!(
186 self.raw.0,
187 ffi::sqlite3_busy_handler(self.raw.0, None, 0 as *mut _)
188 );
189 }
190 Ok(())
191 }
192
193 #[doc(hidden)]
194 #[inline]
195 pub fn as_raw(&self) -> *mut ffi::sqlite3 {
196 self.raw.0
197 }
198
199 pub fn last(&mut self) -> Option<Error> {
201 let raw = self.as_raw();
202 unsafe {
203 let code = ffi::sqlite3_errcode(raw);
204 if code == ffi::SQLITE_OK {
205 return None;
206 }
207 let message = ffi::sqlite3_errmsg(raw);
208 if message.is_null() {
209 return None;
210 }
211 Some(Error {
212 code: Some(code as isize),
213 message: Some(c_str_to_string!(message)),
214 })
215 }
216 }
217}
218
219impl Drop for Connection {
220 #[inline]
221 #[allow(unused_must_use)]
222 fn drop(&mut self) {
223 self.remove_busy_handler();
224 unsafe { ffi::sqlite3_close(self.raw.0) };
225 }
226}
227
228impl OpenFlags {
229 #[inline]
231 pub fn new() -> Self {
232 OpenFlags(0)
233 }
234
235 pub fn set_create(mut self) -> Self {
237 self.0 |= ffi::SQLITE_OPEN_CREATE;
238 self
239 }
240
241 pub fn set_full_mutex(mut self) -> Self {
245 self.0 |= ffi::SQLITE_OPEN_FULLMUTEX;
246 self
247 }
248
249 pub fn set_no_mutex(mut self) -> Self {
253 self.0 |= ffi::SQLITE_OPEN_NOMUTEX;
254 self
255 }
256
257 pub fn set_read_only(mut self) -> Self {
259 self.0 |= ffi::SQLITE_OPEN_READONLY;
260 self
261 }
262
263 pub fn set_read_write(mut self) -> Self {
265 self.0 |= ffi::SQLITE_OPEN_READWRITE;
266 self
267 }
268}
269
270impl Deref for ConnectionWithFullMutex {
271 type Target = Connection;
272
273 #[inline]
274 fn deref(&self) -> &Self::Target {
275 &self.0
276 }
277}
278
279impl DerefMut for ConnectionWithFullMutex {
280 #[inline]
281 fn deref_mut(&mut self) -> &mut Self::Target {
282 &mut self.0
283 }
284}
285
286unsafe impl Sync for ConnectionWithFullMutex {}
287
288unsafe impl Send for Raw {}
289
290extern "C" fn busy_callback<F>(callback: *mut c_void, attempts: c_int) -> c_int
291where
292 F: FnMut(usize) -> bool,
293{
294 unsafe {
295 if (*(callback as *mut F))(attempts as usize) {
296 1
297 } else {
298 0
299 }
300 }
301}
302
303extern "C" fn process_callback<F>(
304 callback: *mut c_void,
305 count: c_int,
306 values: *mut *mut c_char,
307 columns: *mut *mut c_char,
308) -> c_int
309where
310 F: FnMut(&[(&str, Option<&str>)]) -> bool,
311{
312 unsafe {
313 let mut pairs = Vec::with_capacity(count as usize);
314 for index in 0..(count as isize) {
315 let column = {
316 let pointer = *columns.offset(index);
317 debug_assert!(!pointer.is_null());
318 c_str_to_str!(pointer).unwrap()
319 };
320 let value = {
321 let pointer = *values.offset(index);
322 if pointer.is_null() {
323 None
324 } else {
325 Some(c_str_to_str!(pointer).unwrap())
326 }
327 };
328 pairs.push((column, value));
329 }
330 if (*(callback as *mut F))(&pairs) {
331 0
332 } else {
333 1
334 }
335 }
336}