kontrak_sqlite/
connection.rs1use ffi;
2use libc::{c_char, c_int, c_void};
3use std::marker::PhantomData;
4use std::path::Path;
5
6use {Result, Statement};
7
8pub struct Connection {
10 raw: *mut ffi::sqlite3,
11 busy_callback: Option<Box<FnMut(usize) -> bool>>,
12 phantom: PhantomData<ffi::sqlite3>,
13}
14
15unsafe impl Send for Connection {}
16
17impl Connection {
18 pub fn open<T: AsRef<Path>>(path: T) -> Result<Connection> {
20 let mut raw = 0 as *mut _;
21 unsafe {
22 ok!(ffi::sqlite3_open_v2(
23 path_to_cstr!(path.as_ref()).as_ptr(),
24 &mut raw,
25 ffi::SQLITE_OPEN_CREATE | ffi::SQLITE_OPEN_READWRITE,
26 0 as *const _,
27 ));
28 }
29 Ok(Connection {
30 raw: raw,
31 busy_callback: None,
32 phantom: PhantomData,
33 })
34 }
35
36 #[inline]
38 pub fn execute<T: AsRef<str>>(&self, statement: T) -> Result<()> {
39 unsafe {
40 ok!(
41 self.raw,
42 ffi::sqlite3_exec(
43 self.raw,
44 str_to_cstr!(statement.as_ref()).as_ptr(),
45 None,
46 0 as *mut _,
47 0 as *mut _,
48 )
49 );
50 }
51 Ok(())
52 }
53
54 #[inline]
60 pub fn iterate<T: AsRef<str>, F>(&self, statement: T, callback: F) -> Result<()>
61 where
62 F: FnMut(&[(&str, Option<&str>)]) -> bool,
63 {
64 unsafe {
65 let callback = Box::new(callback);
66 ok!(
67 self.raw,
68 ffi::sqlite3_exec(
69 self.raw,
70 str_to_cstr!(statement.as_ref()).as_ptr(),
71 Some(process_callback::<F>),
72 &*callback as *const F as *mut F as *mut _,
73 0 as *mut _,
74 )
75 );
76 }
77 Ok(())
78 }
79
80 #[inline]
82 pub fn prepare<'l, T: AsRef<str>>(&'l self, statement: T) -> Result<Statement<'l>> {
83 ::statement::new(self.raw, statement)
84 }
85
86 pub fn set_busy_handler<F>(&mut self, callback: F) -> Result<()>
92 where
93 F: FnMut(usize) -> bool + Send + 'static,
94 {
95 try!(self.remove_busy_handler());
96 unsafe {
97 let callback = Box::new(callback);
98 let result = ffi::sqlite3_busy_handler(
99 self.raw,
100 Some(busy_callback::<F>),
101 &*callback as *const F as *mut F as *mut _,
102 );
103 self.busy_callback = Some(callback);
104 ok!(self.raw, result);
105 }
106 Ok(())
107 }
108
109 #[inline]
112 pub fn set_busy_timeout(&mut self, milliseconds: usize) -> Result<()> {
113 unsafe {
114 ok!(
115 self.raw,
116 ffi::sqlite3_busy_timeout(self.raw, milliseconds as c_int)
117 );
118 }
119 Ok(())
120 }
121
122 #[inline]
124 pub fn remove_busy_handler(&mut self) -> Result<()> {
125 self.busy_callback = None;
126 unsafe {
127 ok!(
128 self.raw,
129 ffi::sqlite3_busy_handler(self.raw, None, 0 as *mut _)
130 );
131 }
132 Ok(())
133 }
134
135 #[inline]
137 pub fn as_raw(&self) -> *mut ffi::sqlite3 {
138 self.raw
139 }
140}
141
142impl Drop for Connection {
143 #[inline]
144 #[allow(unused_must_use)]
145 fn drop(&mut self) {
146 self.remove_busy_handler();
147 unsafe { ffi::sqlite3_close(self.raw) };
148 }
149}
150
151extern "C" fn busy_callback<F>(callback: *mut c_void, attempts: c_int) -> c_int
152where
153 F: FnMut(usize) -> bool,
154{
155 unsafe {
156 if (*(callback as *mut F))(attempts as usize) {
157 1
158 } else {
159 0
160 }
161 }
162}
163
164extern "C" fn process_callback<F>(
165 callback: *mut c_void,
166 count: c_int,
167 values: *mut *mut c_char,
168 columns: *mut *mut c_char,
169) -> c_int
170where
171 F: FnMut(&[(&str, Option<&str>)]) -> bool,
172{
173 unsafe {
174 let mut pairs = Vec::with_capacity(count as usize);
175
176 for i in 0..(count as isize) {
177 let column = {
178 let pointer = *columns.offset(i);
179 debug_assert!(!pointer.is_null());
180 c_str_to_str!(pointer).unwrap()
181 };
182 let value = {
183 let pointer = *values.offset(i);
184 if pointer.is_null() {
185 None
186 } else {
187 Some(c_str_to_str!(pointer).unwrap())
188 }
189 };
190 pairs.push((column, value));
191 }
192
193 if (*(callback as *mut F))(&pairs) {
194 0
195 } else {
196 1
197 }
198 }
199}