1 extern crate libsqlite3_sys as ffi;
2
3 use std::ffi::{CStr, CString};
4 use std::io::{stderr, Write};
5 use std::os::raw as libc;
6 use std::ptr::NonNull;
7 use std::{mem, ptr, slice, str};
8
9 use super::serialized_value::SerializedValue;
10 use result::Error::DatabaseError;
11 use result::*;
12
13 #[allow(missing_debug_implementations, missing_copy_implementations)]
14 pub struct RawConnection {
15 pub(crate) internal_connection: NonNull<ffi::sqlite3>,
16 }
17
18 impl RawConnection {
establish(database_url: &str) -> ConnectionResult<Self>19 pub fn establish(database_url: &str) -> ConnectionResult<Self> {
20 let mut conn_pointer = ptr::null_mut();
21 let database_url = CString::new(database_url)?;
22 let connection_status =
23 unsafe { ffi::sqlite3_open(database_url.as_ptr(), &mut conn_pointer) };
24
25 match connection_status {
26 ffi::SQLITE_OK => {
27 let conn_pointer = unsafe { NonNull::new_unchecked(conn_pointer) };
28 Ok(RawConnection {
29 internal_connection: conn_pointer,
30 })
31 }
32 err_code => {
33 let message = super::error_message(err_code);
34 Err(ConnectionError::BadConnection(message.into()))
35 }
36 }
37 }
38
exec(&self, query: &str) -> QueryResult<()>39 pub fn exec(&self, query: &str) -> QueryResult<()> {
40 let mut err_msg = ptr::null_mut();
41 let query = CString::new(query)?;
42 let callback_fn = None;
43 let callback_arg = ptr::null_mut();
44 unsafe {
45 ffi::sqlite3_exec(
46 self.internal_connection.as_ptr(),
47 query.as_ptr(),
48 callback_fn,
49 callback_arg,
50 &mut err_msg,
51 );
52 }
53
54 if err_msg.is_null() {
55 Ok(())
56 } else {
57 let msg = convert_to_string_and_free(err_msg);
58 let error_kind = DatabaseErrorKind::__Unknown;
59 Err(DatabaseError(error_kind, Box::new(msg)))
60 }
61 }
62
rows_affected_by_last_query(&self) -> usize63 pub fn rows_affected_by_last_query(&self) -> usize {
64 unsafe { ffi::sqlite3_changes(self.internal_connection.as_ptr()) as usize }
65 }
66
register_sql_function<F>( &self, fn_name: &str, num_args: usize, deterministic: bool, f: F, ) -> QueryResult<()> where F: FnMut(&Self, &[*mut ffi::sqlite3_value]) -> QueryResult<SerializedValue> + Send + 'static,67 pub fn register_sql_function<F>(
68 &self,
69 fn_name: &str,
70 num_args: usize,
71 deterministic: bool,
72 f: F,
73 ) -> QueryResult<()>
74 where
75 F: FnMut(&Self, &[*mut ffi::sqlite3_value]) -> QueryResult<SerializedValue>
76 + Send
77 + 'static,
78 {
79 let fn_name = CString::new(fn_name)?;
80 let mut flags = ffi::SQLITE_UTF8;
81 if deterministic {
82 flags |= ffi::SQLITE_DETERMINISTIC;
83 }
84 let callback_fn = Box::into_raw(Box::new(f));
85
86 let result = unsafe {
87 ffi::sqlite3_create_function_v2(
88 self.internal_connection.as_ptr(),
89 fn_name.as_ptr(),
90 num_args as _,
91 flags,
92 callback_fn as *mut _,
93 Some(run_custom_function::<F>),
94 None,
95 None,
96 Some(destroy_boxed_fn::<F>),
97 )
98 };
99
100 if result == ffi::SQLITE_OK {
101 Ok(())
102 } else {
103 let error_message = super::error_message(result);
104 Err(DatabaseError(
105 DatabaseErrorKind::__Unknown,
106 Box::new(error_message.to_string()),
107 ))
108 }
109 }
110 }
111
112 impl Drop for RawConnection {
drop(&mut self)113 fn drop(&mut self) {
114 use std::thread::panicking;
115
116 let close_result = unsafe { ffi::sqlite3_close(self.internal_connection.as_ptr()) };
117 if close_result != ffi::SQLITE_OK {
118 let error_message = super::error_message(close_result);
119 if panicking() {
120 write!(
121 stderr(),
122 "Error closing SQLite connection: {}",
123 error_message
124 )
125 .expect("Error writing to `stderr`");
126 } else {
127 panic!("Error closing SQLite connection: {}", error_message);
128 }
129 }
130 }
131 }
132
convert_to_string_and_free(err_msg: *const libc::c_char) -> String133 fn convert_to_string_and_free(err_msg: *const libc::c_char) -> String {
134 let msg = unsafe {
135 let bytes = CStr::from_ptr(err_msg).to_bytes();
136 // sqlite is documented to return utf8 strings here
137 str::from_utf8_unchecked(bytes).into()
138 };
139 unsafe { ffi::sqlite3_free(err_msg as *mut libc::c_void) };
140 msg
141 }
142
143 #[allow(warnings)]
run_custom_function<F>( ctx: *mut ffi::sqlite3_context, num_args: libc::c_int, value_ptr: *mut *mut ffi::sqlite3_value, ) where F: FnMut(&RawConnection, &[*mut ffi::sqlite3_value]) -> QueryResult<SerializedValue> + Send + 'static,144 extern "C" fn run_custom_function<F>(
145 ctx: *mut ffi::sqlite3_context,
146 num_args: libc::c_int,
147 value_ptr: *mut *mut ffi::sqlite3_value,
148 ) where
149 F: FnMut(&RawConnection, &[*mut ffi::sqlite3_value]) -> QueryResult<SerializedValue>
150 + Send
151 + 'static,
152 {
153 static NULL_DATA_ERR: &str = "An unknown error occurred. sqlite3_user_data returned a null pointer. This should never happen.";
154 static NULL_CONN_ERR: &str = "An unknown error occurred. sqlite3_context_db_handle returned a null pointer. This should never happen.";
155
156 unsafe {
157 let data_ptr = ffi::sqlite3_user_data(ctx);
158 let data_ptr = data_ptr as *mut F;
159 let f = match data_ptr.as_mut() {
160 Some(f) => f,
161 None => {
162 ffi::sqlite3_result_error(
163 ctx,
164 NULL_DATA_ERR.as_ptr() as *const _ as *const _,
165 NULL_DATA_ERR.len() as _,
166 );
167 return;
168 }
169 };
170
171 let args = slice::from_raw_parts(value_ptr, num_args as _);
172 let conn = match NonNull::new(ffi::sqlite3_context_db_handle(ctx)) {
173 Some(conn) => RawConnection {
174 internal_connection: conn,
175 },
176 None => {
177 ffi::sqlite3_result_error(
178 ctx,
179 NULL_DATA_ERR.as_ptr() as *const _ as *const _,
180 NULL_DATA_ERR.len() as _,
181 );
182 return;
183 }
184 };
185 match f(&conn, args) {
186 Ok(value) => value.result_of(ctx),
187 Err(e) => {
188 let msg = e.to_string();
189 ffi::sqlite3_result_error(ctx, msg.as_ptr() as *const _, msg.len() as _);
190 }
191 }
192
193 mem::forget(conn);
194 }
195 }
196
destroy_boxed_fn<F>(data: *mut libc::c_void) where F: FnMut(&RawConnection, &[*mut ffi::sqlite3_value]) -> QueryResult<SerializedValue> + Send + 'static,197 extern "C" fn destroy_boxed_fn<F>(data: *mut libc::c_void)
198 where
199 F: FnMut(&RawConnection, &[*mut ffi::sqlite3_value]) -> QueryResult<SerializedValue>
200 + Send
201 + 'static,
202 {
203 let ptr = data as *mut F;
204 unsafe { Box::from_raw(ptr) };
205 }
206