1use crate::{ffi, Error, Result, Statement};
2use std::ffi::CStr;
3
4mod sealed {
5 use std::ffi::CStr;
6 pub trait Sealed {}
9 impl Sealed for usize {}
10 impl Sealed for &str {}
11 impl Sealed for &CStr {}
12}
13
14pub trait BindIndex: sealed::Sealed {
18 fn idx(&self, stmt: &Statement<'_>) -> Result<usize>;
21}
22
23impl BindIndex for usize {
24 #[inline]
25 fn idx(&self, _: &Statement<'_>) -> Result<usize> {
26 Ok(*self)
28 }
29}
30
31impl BindIndex for &'_ str {
32 fn idx(&self, stmt: &Statement<'_>) -> Result<usize> {
33 match stmt.parameter_index(self)? {
34 Some(idx) => Ok(idx),
35 None => Err(Error::InvalidParameterName(self.to_string())),
36 }
37 }
38}
39impl BindIndex for &CStr {
41 fn idx(&self, stmt: &Statement<'_>) -> Result<usize> {
42 let r = unsafe { ffi::sqlite3_bind_parameter_index(stmt.ptr(), self.as_ptr()) };
43 match r {
44 0 => Err(Error::InvalidParameterName(
45 self.to_string_lossy().to_string(),
46 )),
47 i => Ok(i as usize),
48 }
49 }
50}
51
52#[cfg(test)]
53mod test {
54 use crate::{ffi, Connection, Error, Result};
55
56 #[test]
57 fn invalid_name() -> Result<()> {
58 let db = Connection::open_in_memory()?;
59 let mut stmt = db.prepare("SELECT 1")?;
60 let err = stmt.raw_bind_parameter(1, 1).unwrap_err();
61 assert_eq!(
62 err.sqlite_error_code(),
63 Some(ffi::ErrorCode::ParameterOutOfRange),
64 );
65 let err = stmt.raw_bind_parameter(":p1", 1).unwrap_err();
66 assert_eq!(err, Error::InvalidParameterName(":p1".to_owned()));
67 let err = stmt.raw_bind_parameter(c"x", 1).unwrap_err();
68 assert_eq!(err, Error::InvalidParameterName("x".to_owned()));
69 Ok(())
70 }
71}