1#![allow(non_upper_case_globals)]
2#![allow(non_snake_case)]
3#![allow(dead_code)]
4
5use crate::{value::Blob, Error};
6pub use linking::*;
7pub use sqlite3types::*;
8use std::{
9 ffi::{c_void, CString},
10 os::raw::{c_char, c_int},
11 ptr,
12};
13
14mod sqlite3funcs;
15mod sqlite3types;
16
17mod linking {
18 include!(concat!(env!("OUT_DIR"), "/linking.rs"));
19}
20
21#[cfg(modern_sqlite)]
24#[macro_export]
25#[doc(hidden)]
26macro_rules! sqlite3_match_version_trampoline {
27 ($($tail:tt)*) => { $crate::sqlite3_match_version!(@modern () $($tail)*) };
28}
29
30#[cfg(not(modern_sqlite))]
31#[macro_export]
32#[doc(hidden)]
33macro_rules! sqlite3_match_version_trampoline {
34 ($($tail:tt)*) => { $crate::sqlite3_match_version!(@old $($tail)*) };
35}
36
37#[macro_export]
70macro_rules! sqlite3_match_version {
71 (@modern ($($body:tt)*) $ver:literal => { $($block:tt)* } $($tail:tt)* ) => {
73 $crate::sqlite3_match_version!(
74 @modern ( $($body)* $ver.. => {
75 $crate::sqlite3_match_version!(@verify $ver);
76 $($block)*
77 })
78 $($tail)*
79 )
80 };
81 (@old $ver:literal => { $($block:tt)* } $($tail:tt)* ) => {{
82 $crate::sqlite3_match_version!(@verify $ver);
83 $crate::sqlite3_match_version!(@old $($tail)*)
84 }};
85
86 (@modern ($($body:tt)*) $ver:literal => $expr:expr, $($tail:tt)* ) => {
88 $crate::sqlite3_match_version!(
89 @modern ( $($body)* $ver.. => {
90 $crate::sqlite3_match_version!(@verify $ver);
91 $expr
92 })
93 $($tail)*
94 )
95 };
96 (@old $ver:literal => $expr:expr, $($tail:tt)* ) => {{
97 $crate::sqlite3_match_version!(@verify $ver);
98 $crate::sqlite3_match_version!(@old $($tail)*)
99 }};
100
101 (@modern ($($body:tt)*) $ver:literal => $expr:expr ) => {
103 compile_error!("non-exhaustive patterns: missing a wildcard pattern");
104 };
105 (@old $ver:literal => $expr:expr ) => {
106 compile_error!("non-exhaustive patterns: missing a wildcard pattern");
107 };
108
109 (@modern ($($body:tt)*) _ => $expr:expr $(,)? ) => {
111 match $crate::SQLITE_VERSION.as_i32() {
112 $($body)*
113 _ => $expr
114 }
115 };
116 (@old _ => $expr:expr $(,)? ) => {
117 $expr
118 };
119
120 (@modern ($($body:tt)*) , $($tail:tt)* ) => {
122 $crate::sqlite3_match_version!(@modern ( $($body)* ) $($tail)*)
123 };
124 (@old , $($tail:tt)* ) => {
125 $crate::sqlite3_match_version!(@old $($tail)*)
126 };
127
128 (@verify $version:literal) => {
129 #[cfg(debug_assertions)]
132 const _: () = {
133 assert!($version >= 3_006_008, stringify!($version is earlier than 3.6.8 (the minimum supported version of SQLite)));
134 assert!($version < 4_000_000, stringify!($version is newer than 4.0.0 (which is not a valid version of SQLite3)));
135 };
136 };
137
138 ( $x:literal => $($tail:tt)* ) => {
140 $crate::sqlite3_match_version_trampoline!($x => $($tail)*)
141 };
142}
143
144#[macro_export]
169macro_rules! sqlite3_require_version {
170 ($version:literal) => {
171 $crate::sqlite3_require_version!($version, Ok(()))
172 };
173
174 ($version:literal, $expr:expr) => {
175 $crate::sqlite3_match_version! {
176 $version => {
177 let ret: Result<_> = $expr;
178 ret
179 }
180 _ => Err(Error::VersionNotSatisfied($version)),
181 }
182 };
183}
184
185pub const unsafe fn sqlite_transient() -> Option<unsafe extern "C" fn(arg1: *mut c_void)> {
191 std::mem::transmute(-1 as isize as usize)
192}
193
194pub fn str_to_sqlite3(val: &str) -> Result<*mut c_char, Error> {
198 if val.is_empty() {
199 return Ok(ptr::null_mut());
200 }
201 let len: usize = val.len().checked_add(1).ok_or(crate::types::SQLITE_NOMEM)?;
202 unsafe {
203 let ptr: *mut c_char = sqlite3_match_version! {
204 3_008_007 => sqlite3_malloc64(len as _) as _,
205 _ => sqlite3_malloc(len as _) as _,
206 };
207 if !ptr.is_null() {
208 ptr::copy_nonoverlapping(val.as_ptr(), ptr as _, len as _);
209 *ptr.add(len - 1) = 0;
210 Ok(ptr)
211 } else {
212 Err(crate::types::SQLITE_NOMEM)
213 }
214 }
215}
216
217pub unsafe fn handle_error(err: impl Into<Error>, msg: *mut *mut c_char) -> c_int {
218 err.into().into_sqlite(msg)
219}
220
221pub unsafe fn handle_result(result: Result<(), Error>, msg: *mut *mut c_char) -> c_int {
222 match result {
223 Ok(_) => SQLITE_OK,
224 Err(e) => handle_error(e, msg),
225 }
226}
227
228pub fn is_version(min: c_int) -> bool {
229 let found = unsafe { sqlite3_libversion_number() };
230 found >= min
231}
232
233pub unsafe extern "C" fn drop_boxed<T>(data: *mut c_void) {
234 drop(Box::<T>::from_raw(data as _));
235}
236
237pub unsafe extern "C" fn drop_cstring(data: *mut c_void) {
238 drop(CString::from_raw(data as _));
239}
240
241pub unsafe extern "C" fn drop_blob(data: *mut c_void) {
242 drop(Blob::from_raw(data));
243}
244
245#[cfg(test)]
246mod test {
247 use crate::sqlite3_match_version;
248
249 fn test_patterns() {
250 let s = sqlite3_match_version! {
251 3_008_008 => "expr,",
252 3_008_007 => { "{expr}" }
253 3_008_006 => { "{expr}," },
254 _ => "fall,",
255 };
256 assert_eq!(s, "expr,");
257 let s = sqlite3_match_version! {
258 3_008_006 => "expr,",
259 _ => "fall"
260 };
261 assert_eq!(s, "expr,");
262 }
263}