rusqlite/
bind.rs

1use crate::{ffi, Error, Result, Statement};
2use std::ffi::CStr;
3
4mod sealed {
5    use std::ffi::CStr;
6    /// This trait exists just to ensure that the only impls of `trait BindIndex`
7    /// that are allowed are ones in this crate.
8    pub trait Sealed {}
9    impl Sealed for usize {}
10    impl Sealed for &str {}
11    impl Sealed for &CStr {}
12}
13
14/// A trait implemented by types that can index into parameters of a statement.
15///
16/// It is only implemented for `usize` and `&str` and `&CStr`.
17pub trait BindIndex: sealed::Sealed {
18    /// Returns the index of the associated parameter, or `Error` if no such
19    /// parameter exists.
20    fn idx(&self, stmt: &Statement<'_>) -> Result<usize>;
21}
22
23impl BindIndex for usize {
24    #[inline]
25    fn idx(&self, _: &Statement<'_>) -> Result<usize> {
26        // No validation
27        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}
39/// C-string literal to avoid alloc
40impl 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}