1use crate::api::answer::Answer;
4use crate::api::ffiext::{self, PointerMut};
5use crate::api::types::SqliteType;
6use crate::error::Error;
7use crate::{err, ffi, Sqlite};
8
9#[derive(Debug)]
11pub struct Query<'db> {
12 pub(in crate::api) sqlite: &'db Sqlite,
14 pub(in crate::api) raw: PointerMut<ffi::sqlite3_stmt>,
16}
17impl<'db> Query<'db> {
18 pub fn bind<T>(self, column: std::ffi::c_int, value: T) -> Result<Self, Error>
23 where
24 SqliteType: TryFrom<T>,
25 <SqliteType as TryFrom<T>>::Error: std::error::Error + Send + 'static,
26 {
27 let value =
29 SqliteType::try_from(value).map_err(|e| err!(with: e, "Failed to convert value into SQLite type"))?;
30 match value {
31 SqliteType::Null => self.bind_null(column)?,
32 SqliteType::Integer(value) => self.bind_integer(column, value)?,
33 SqliteType::Real(value) => self.bind_real(column, value)?,
34 SqliteType::Text(value) => self.bind_text(column, value)?,
35 SqliteType::Blob(value) => self.bind_blob(column, value)?,
36 }
37 Ok(self)
38 }
39 fn bind_null(&self, column: std::ffi::c_int) -> Result<(), Error> {
41 let retval = unsafe { ffi::sqlite3_bind_null(self.raw.as_ptr(), column) };
42 unsafe { ffiext::sqlite3_check_result(retval, self.sqlite.raw.as_ptr()) }
43 }
44 fn bind_integer(&self, column: std::ffi::c_int, value: i64) -> Result<(), Error> {
46 let retval = unsafe { ffi::sqlite3_bind_int64(self.raw.as_ptr(), column, value) };
47 unsafe { ffiext::sqlite3_check_result(retval, self.sqlite.raw.as_ptr()) }
48 }
49 fn bind_real(&self, column: std::ffi::c_int, value: f64) -> Result<(), Error> {
51 let retval = unsafe { ffi::sqlite3_bind_double(self.raw.as_ptr(), column, value) };
52 unsafe { ffiext::sqlite3_check_result(retval, self.sqlite.raw.as_ptr()) }
53 }
54 fn bind_text(&self, column: std::ffi::c_int, value: String) -> Result<(), Error> {
56 let retval = unsafe {
57 ffi::sqlite3_bind_text64(
59 self.raw.as_ptr(),
60 column,
61 value.as_ptr() as _,
62 value.len() as _,
63 ffi::sqlite3_transient(),
64 ffi::SQLITE_UTF8 as _,
65 )
66 };
67 unsafe { ffiext::sqlite3_check_result(retval, self.sqlite.raw.as_ptr()) }
68 }
69 fn bind_blob(&self, column: std::ffi::c_int, value: Vec<u8>) -> Result<(), Error> {
71 let retval = unsafe {
72 ffi::sqlite3_bind_blob64(
74 self.raw.as_ptr(),
75 column,
76 value.as_ptr() as _,
77 value.len() as _,
78 ffi::sqlite3_transient(),
79 )
80 };
81 unsafe { ffiext::sqlite3_check_result(retval, self.sqlite.raw.as_ptr()) }
82 }
83
84 pub fn execute(self) -> Result<Answer<'db>, Error> {
86 let mut result = Answer { sqlite: self.sqlite, raw: self.raw, has_row: false };
88 result.step()?;
89
90 Ok(result)
92 }
93}