use super::Statement;
use crate::{ffi, sqlite3_match_version, sqlite3_require_version, types::*, value::*};
use sealed::sealed;
#[macro_export]
macro_rules! params {
($($val:expr),* $(,)?) => {
|stmt: &mut $crate::query::Statement| {{
#![allow(unused_assignments)]
use $crate::query::ToParam;
let mut i = 1i32;
$(
$val.bind_param(stmt, i)?;
i += 1;
)*
Ok(())
}}
}
}
pub trait Params {
fn bind_params(self, stmt: &mut Statement) -> Result<()>;
}
impl Params for () {
fn bind_params(self, _: &mut Statement) -> Result<()> {
Ok(())
}
}
impl<T> Params for T
where
T: FnOnce(&mut Statement) -> Result<()>,
{
fn bind_params(self, stmt: &mut Statement) -> Result<()> {
self(stmt)
}
}
impl<T: ToParam> Params for Vec<T> {
fn bind_params(self, stmt: &mut Statement) -> Result<()> {
for (pos, val) in self.into_iter().enumerate() {
val.bind_param(stmt, pos as i32 + 1)?;
}
Ok(())
}
}
impl<T: ToParam, const N: usize> Params for [T; N] {
fn bind_params(self, stmt: &mut Statement) -> Result<()> {
for (pos, val) in self.into_iter().enumerate() {
val.bind_param(stmt, pos as i32 + 1)?;
}
Ok(())
}
}
impl Params for &mut [&mut ValueRef] {
fn bind_params(self, stmt: &mut Statement) -> Result<()> {
for (pos, val) in self.iter_mut().enumerate() {
val.bind_param(stmt, pos as i32 + 1)?;
}
Ok(())
}
}
#[sealed]
pub trait ToParam {
fn bind_param(self, stmt: &mut Statement, position: i32) -> Result<()>;
}
macro_rules! to_param {
($(#[$attr:meta])* $ty:ty as ($stmt:ident, $pos:ident, $val:ident) => $impl:expr) => {
$(#[$attr])*
#[sealed]
impl ToParam for $ty {
fn bind_param(self, stmt: &mut Statement, $pos: i32) -> Result<()> {
#[allow(clippy::let_unit_value)]
let $val = self;
let $stmt = stmt.base;
Error::from_sqlite(unsafe { $impl })
}
}
};
}
to_param!(() as (stmt, pos, _val) => ffi::sqlite3_bind_null(stmt, pos));
to_param!(bool as (stmt, pos, val) => ffi::sqlite3_bind_int(stmt, pos, val as i32));
to_param!(i64 as (stmt, pos, val) => ffi::sqlite3_bind_int64(stmt, pos, val));
to_param!(f64 as (stmt, pos, val) => ffi::sqlite3_bind_double(stmt, pos, val));
to_param!(Blob as (stmt, pos, val) => {
let len = val.len();
sqlite3_match_version! {
3_008_007 => ffi::sqlite3_bind_blob64(stmt, pos, val.into_raw(), len as _, Some(ffi::drop_blob)),
_ => ffi::sqlite3_bind_blob(stmt, pos, val.into_raw(), len as _, Some(ffi::drop_blob)),
}
});
to_param!(&mut ValueRef as (stmt, pos, val) => ffi::sqlite3_bind_value(stmt, pos, val.as_ptr()));
#[sealed]
impl ToParam for &str {
fn bind_param(self, stmt: &mut Statement, pos: i32) -> Result<()> {
let val = self.as_bytes();
let len = val.len();
Error::from_sqlite(unsafe {
sqlite3_match_version! {
3_008_007 => ffi::sqlite3_bind_text64(stmt.base, pos, val.as_ptr() as _, len as _, ffi::sqlite_transient(), ffi::SQLITE_UTF8 as _),
_ => ffi::sqlite3_bind_text(stmt.base, pos, val.as_ptr() as _, len as _, ffi::sqlite_transient()),
}
})
}
}
#[sealed]
impl ToParam for &ValueRef {
fn bind_param(self, stmt: &mut Statement, pos: i32) -> Result<()> {
unsafe { Error::from_sqlite(ffi::sqlite3_bind_value(stmt.base, pos, self.as_ptr())) }
}
}
#[sealed]
impl ToParam for &[u8] {
fn bind_param(self, stmt: &mut Statement, pos: i32) -> Result<()> {
let len = self.len();
unsafe {
Error::from_sqlite(sqlite3_match_version! {
3_008_007 => ffi::sqlite3_bind_blob64(
stmt.base,
pos,
self.as_ptr() as _,
len as _,
ffi::sqlite_transient(),
),
_ => ffi::sqlite3_bind_blob(
stmt.base,
pos,
self.as_ptr() as _,
len as _,
ffi::sqlite_transient(),
),
})
}
}
}
#[sealed]
impl<const N: usize> ToParam for &[u8; N] {
fn bind_param(self, stmt: &mut Statement, pos: i32) -> Result<()> {
self.as_slice().bind_param(stmt, pos)
}
}
#[sealed]
impl ToParam for Value {
fn bind_param(self, stmt: &mut Statement, pos: i32) -> Result<()> {
match self {
Value::Integer(x) => x.bind_param(stmt, pos),
Value::Float(x) => x.bind_param(stmt, pos),
Value::Text(x) => x.bind_param(stmt, pos),
Value::Blob(x) => x.bind_param(stmt, pos),
Value::Null => ().bind_param(stmt, pos),
}
}
}
#[sealed]
impl<T> ToParam for Option<T>
where
T: ToParam,
{
fn bind_param(self, stmt: &mut Statement, pos: i32) -> Result<()> {
match self {
Some(x) => x.bind_param(stmt, pos),
None => ().bind_param(stmt, pos),
}
}
}
#[sealed]
impl<T: 'static> ToParam for PassedRef<T> {
fn bind_param(self, stmt: &mut Statement, pos: i32) -> Result<()> {
let _ = (POINTER_TAG, &stmt, pos);
sqlite3_require_version!(3_020_000, unsafe {
Error::from_sqlite(ffi::sqlite3_bind_pointer(
stmt.base,
pos,
Box::into_raw(Box::new(self)) as _,
POINTER_TAG,
Some(ffi::drop_boxed::<PassedRef<T>>),
))
})
}
}
#[sealed]
impl<K, V> ToParam for (K, V)
where
K: Into<Vec<u8>>,
V: ToParam,
{
fn bind_param(self, stmt: &mut Statement, _: i32) -> Result<()> {
let pos = stmt.parameter_position(self.0);
match pos {
Some(pos) => self.1.bind_param(stmt, pos.get()),
None => Err(SQLITE_RANGE),
}
}
}