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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
use ffi;
use libc::{c_char, c_int, c_void};
use std::marker::PhantomData;
use std::path::Path;
use {Result, Statement};
pub struct Connection {
raw: *mut ffi::sqlite3,
busy_callback: Option<Box<FnMut(usize) -> bool>>,
phantom: PhantomData<ffi::sqlite3>,
}
impl Connection {
pub fn open<T: AsRef<Path>>(path: T) -> Result<Connection> {
let mut raw = 0 as *mut _;
unsafe {
ok!(ffi::sqlite3_open_v2(path_to_cstr!(path.as_ref()).as_ptr(), &mut raw,
ffi::SQLITE_OPEN_CREATE | ffi::SQLITE_OPEN_READWRITE,
0 as *const _));
}
Ok(Connection { raw: raw, busy_callback: None, phantom: PhantomData })
}
#[inline]
pub fn execute<T: AsRef<str>>(&self, statement: T) -> Result<()> {
unsafe {
ok!(self.raw, ffi::sqlite3_exec(self.raw, str_to_cstr!(statement.as_ref()).as_ptr(),
None, 0 as *mut _, 0 as *mut _));
}
Ok(())
}
#[inline]
pub fn iterate<T: AsRef<str>, F>(&self, statement: T, callback: F) -> Result<()>
where F: FnMut(&[(&str, Option<&str>)]) -> bool
{
unsafe {
let callback = Box::new(callback);
ok!(self.raw, ffi::sqlite3_exec(self.raw, str_to_cstr!(statement.as_ref()).as_ptr(),
Some(process_callback::<F>),
&*callback as *const F as *mut F as *mut _,
0 as *mut _));
}
Ok(())
}
#[inline]
pub fn prepare<'l, T: AsRef<str>>(&'l self, statement: T) -> Result<Statement<'l>> {
::statement::new(self.raw, statement)
}
pub fn set_busy_handler<F>(&mut self, callback: F) -> Result<()>
where F: FnMut(usize) -> bool + 'static
{
try!(self.remove_busy_handler());
unsafe {
let callback = Box::new(callback);
let result = ffi::sqlite3_busy_handler(self.raw, Some(busy_callback::<F>),
&*callback as *const F as *mut F as *mut _);
self.busy_callback = Some(callback);
ok!(self.raw, result);
}
Ok(())
}
#[inline]
pub fn set_busy_timeout(&mut self, milliseconds: usize) -> Result<()> {
unsafe { ok!(self.raw, ffi::sqlite3_busy_timeout(self.raw, milliseconds as c_int)) };
Ok(())
}
#[inline]
pub fn remove_busy_handler(&mut self) -> Result<()> {
self.busy_callback = None;
unsafe { ok!(self.raw, ffi::sqlite3_busy_handler(self.raw, None, 0 as *mut _)) };
Ok(())
}
}
impl Drop for Connection {
#[cfg(not(feature = "sqlite3-close-v2"))]
#[inline]
#[allow(unused_must_use)]
fn drop(&mut self) {
self.remove_busy_handler();
unsafe { ffi::sqlite3_close(self.raw) };
}
#[cfg(feature = "sqlite3-close-v2")]
#[inline]
#[allow(unused_must_use)]
fn drop(&mut self) {
self.remove_busy_handler();
unsafe { ffi::sqlite3_close_v2(self.raw) };
}
}
extern fn busy_callback<F>(callback: *mut c_void, attempts: c_int) -> c_int
where F: FnMut(usize) -> bool
{
unsafe { if (*(callback as *mut F))(attempts as usize) { 1 } else { 0 } }
}
extern fn process_callback<F>(callback: *mut c_void, count: c_int, values: *mut *mut c_char,
columns: *mut *mut c_char) -> c_int
where F: FnMut(&[(&str, Option<&str>)]) -> bool
{
unsafe {
let mut pairs = Vec::with_capacity(count as usize);
for i in 0..(count as isize) {
let column = {
let pointer = *columns.offset(i);
debug_assert!(!pointer.is_null());
c_str_to_str!(pointer).unwrap()
};
let value = {
let pointer = *values.offset(i);
if pointer.is_null() {
None
} else {
Some(c_str_to_str!(pointer).unwrap())
}
};
pairs.push((column, value));
}
if (*(callback as *mut F))(&pairs) { 0 } else { 1 }
}
}