Skip to main content

diesel/sqlite/connection/
stmt.rs

1#![allow(unsafe_code)] // fii code
2use super::bind_collector::{SqliteBindCollector, SqliteBindValueRef};
3use super::raw::RawConnection;
4use super::sqlite_value::OwnedSqliteValue;
5use crate::connection::Instrumentation;
6use crate::connection::statement_cache::{MaybeCached, PrepareForCache, PreparedStatement};
7use crate::query_builder::{QueryFragment, QueryId};
8use crate::result::Error::DatabaseError;
9use crate::result::*;
10use crate::sqlite::{Sqlite, SqliteType};
11use alloc::boxed::Box;
12use alloc::ffi::CString;
13use alloc::string::String;
14use alloc::vec::Vec;
15use core::cell::OnceCell;
16use core::ffi as libc;
17use core::ffi::CStr;
18use core::ptr::{self, NonNull};
19#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
20use libsqlite3_sys as ffi;
21#[cfg(all(target_family = "wasm", target_os = "unknown"))]
22use sqlite_wasm_rs as ffi;
23
24pub(super) struct Statement {
25    inner_statement: NonNull<ffi::sqlite3_stmt>,
26}
27
28// This relies on the invariant that RawConnection or Statement are never
29// leaked. If a reference to one of those was held on a different thread, this
30// would not be thread safe.
31#[allow(unsafe_code)]
32unsafe impl Send for Statement {}
33
34impl PreparedStatement for Statement {
35    fn parameter_count(&self) -> u64 {
36        // SAFETY: inner_statement is a valid sqlite3_stmt pointer to a non-deallocated statement
37        unsafe {
38            ffi::sqlite3_bind_parameter_count(self.inner_statement.as_ptr())
39                .try_into()
40                .unwrap_or(0)
41        }
42    }
43}
44
45impl Statement {
46    pub(super) fn prepare(
47        raw_connection: &RawConnection,
48        sql: &str,
49        is_cached: PrepareForCache,
50        _: &[SqliteType],
51    ) -> QueryResult<Self> {
52        let mut stmt = ptr::null_mut();
53        let mut unused_portion = ptr::null();
54        let n_byte = sql
55            .len()
56            .try_into()
57            .map_err(|e| Error::SerializationError(Box::new(e)))?;
58        // the cast for `ffi::SQLITE_PREPARE_PERSISTENT` is required for old libsqlite3-sys versions
59        #[allow(clippy::unnecessary_cast)]
60        let prepare_result = unsafe {
61            ffi::sqlite3_prepare_v3(
62                raw_connection.internal_connection.as_ptr(),
63                CString::new(sql)?.as_ptr(),
64                n_byte,
65                if #[allow(non_exhaustive_omitted_patterns)] match is_cached {
    PrepareForCache::Yes { counter: _ } => true,
    _ => false,
}matches!(is_cached, PrepareForCache::Yes { counter: _ }) {
66                    ffi::SQLITE_PREPARE_PERSISTENT as u32
67                } else {
68                    0
69                },
70                &mut stmt,
71                &mut unused_portion,
72            )
73        };
74
75        ensure_sqlite_ok(prepare_result, raw_connection.internal_connection.as_ptr())?;
76
77        // sqlite3_prepare_v3 returns a null pointer for empty statements. This includes
78        // empty or only whitespace strings or any other non-op query string like a comment
79        let inner_statement = NonNull::new(stmt).ok_or_else(|| {
80            crate::result::Error::QueryBuilderError(Box::new(crate::result::EmptyQuery))
81        })?;
82        Ok(Statement { inner_statement })
83    }
84
85    // The caller of this function has to ensure that:
86    // * Any buffer provided as `SqliteBindValue::BorrowedBinary`, `SqliteBindValue::Binary`
87    // `SqliteBindValue::String` or `SqliteBindValue::BorrowedString` is valid
88    // till either a new value is bound to the same parameter or the underlying
89    // prepared statement is dropped.
90    unsafe fn bind(
91        &mut self,
92        tpe: SqliteType,
93        value: SqliteBindValueRef<'_>,
94        bind_index: i32,
95    ) -> QueryResult<Option<NonNull<[u8]>>> {
96        let mut ret_ptr = None;
97        let result = match (tpe, value) {
98            (_, SqliteBindValueRef::Null) => unsafe {
99                ffi::sqlite3_bind_null(self.inner_statement.as_ptr(), bind_index)
100            },
101            (SqliteType::Binary, SqliteBindValueRef::BorrowedBinary(bytes)) => {
102                let n = bytes
103                    .len()
104                    .try_into()
105                    .map_err(|e| Error::SerializationError(Box::new(e)))?;
106                unsafe {
107                    ffi::sqlite3_bind_blob(
108                        self.inner_statement.as_ptr(),
109                        bind_index,
110                        bytes.as_ptr() as *const libc::c_void,
111                        n,
112                        ffi::SQLITE_STATIC(),
113                    )
114                }
115            }
116            (SqliteType::Binary, SqliteBindValueRef::Binary(mut bytes)) => {
117                let len = bytes
118                    .len()
119                    .try_into()
120                    .map_err(|e| Error::SerializationError(Box::new(e)))?;
121                // We need a separate pointer here to pass it to sqlite
122                // as the returned pointer is a pointer to a dyn sized **slice**
123                // and not the pointer to the first element of the slice
124                let ptr = bytes.as_mut_ptr();
125                ret_ptr = NonNull::new(Box::into_raw(bytes));
126                unsafe {
127                    ffi::sqlite3_bind_blob(
128                        self.inner_statement.as_ptr(),
129                        bind_index,
130                        ptr as *const libc::c_void,
131                        len,
132                        ffi::SQLITE_STATIC(),
133                    )
134                }
135            }
136            (SqliteType::Text, SqliteBindValueRef::BorrowedString(bytes)) => {
137                let len = bytes
138                    .len()
139                    .try_into()
140                    .map_err(|e| Error::SerializationError(Box::new(e)))?;
141                unsafe {
142                    ffi::sqlite3_bind_text(
143                        self.inner_statement.as_ptr(),
144                        bind_index,
145                        bytes.as_ptr() as *const libc::c_char,
146                        len,
147                        ffi::SQLITE_STATIC(),
148                    )
149                }
150            }
151            (SqliteType::Text, SqliteBindValueRef::String(bytes)) => {
152                let mut bytes = Box::<[u8]>::from(bytes);
153                let len = bytes
154                    .len()
155                    .try_into()
156                    .map_err(|e| Error::SerializationError(Box::new(e)))?;
157                // We need a separate pointer here to pass it to sqlite
158                // as the returned pointer is a pointer to a dyn sized **slice**
159                // and not the pointer to the first element of the slice
160                let ptr = bytes.as_mut_ptr();
161                ret_ptr = NonNull::new(Box::into_raw(bytes));
162                unsafe {
163                    ffi::sqlite3_bind_text(
164                        self.inner_statement.as_ptr(),
165                        bind_index,
166                        ptr as *const libc::c_char,
167                        len,
168                        ffi::SQLITE_STATIC(),
169                    )
170                }
171            }
172            (SqliteType::Float, SqliteBindValueRef::F64(value))
173            | (SqliteType::Double, SqliteBindValueRef::F64(value)) => unsafe {
174                ffi::sqlite3_bind_double(
175                    self.inner_statement.as_ptr(),
176                    bind_index,
177                    value as libc::c_double,
178                )
179            },
180            (SqliteType::SmallInt, SqliteBindValueRef::I32(value))
181            | (SqliteType::Integer, SqliteBindValueRef::I32(value)) => unsafe {
182                ffi::sqlite3_bind_int(self.inner_statement.as_ptr(), bind_index, value)
183            },
184            (SqliteType::Long, SqliteBindValueRef::I64(value)) => unsafe {
185                ffi::sqlite3_bind_int64(self.inner_statement.as_ptr(), bind_index, value)
186            },
187            (t, b) => {
188                return Err(Error::SerializationError(
189                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("Type mismatch: Expected {0:?}, got {1}",
                t, b))
    })alloc::format!("Type mismatch: Expected {t:?}, got {b}").into(),
190                ));
191            }
192        };
193        match ensure_sqlite_ok(result, self.raw_connection()) {
194            Ok(()) => Ok(ret_ptr),
195            Err(e) => {
196                if let Some(ptr) = ret_ptr {
197                    // This is a `NonNul` ptr so it cannot be null
198                    // It points to a slice internally as we did not apply
199                    // any cast above.
200                    core::mem::drop(unsafe { Box::from_raw(ptr.as_ptr()) })
201                }
202                Err(e)
203            }
204        }
205    }
206
207    fn reset(&mut self) {
208        unsafe { ffi::sqlite3_reset(self.inner_statement.as_ptr()) };
209    }
210
211    /// Steps the statement once for its side effects.
212    #[cfg(not(miri))]
213    pub(super) fn run(&mut self) -> QueryResult<()> {
214        // SAFETY: `inner_statement` stays a live prepared statement until `Drop`.
215        match unsafe { ffi::sqlite3_step(self.inner_statement.as_ptr()) } {
216            ffi::SQLITE_DONE | ffi::SQLITE_ROW => Ok(()),
217            _ => {
218                let error = last_error(self.raw_connection());
219                // Clears the step error so that `Drop` finalizes successfully.
220                self.reset();
221                Err(error)
222            }
223        }
224    }
225
226    fn clear_bindings(&mut self) {
227        unsafe { ffi::sqlite3_clear_bindings(self.inner_statement.as_ptr()) };
228    }
229
230    fn raw_connection(&self) -> *mut ffi::sqlite3 {
231        unsafe { ffi::sqlite3_db_handle(self.inner_statement.as_ptr()) }
232    }
233}
234
235pub(super) fn ensure_sqlite_ok(
236    code: libc::c_int,
237    raw_connection: *mut ffi::sqlite3,
238) -> QueryResult<()> {
239    if code == ffi::SQLITE_OK {
240        Ok(())
241    } else {
242        Err(last_error(raw_connection))
243    }
244}
245
246fn last_error(raw_connection: *mut ffi::sqlite3) -> Error {
247    let error_message = last_error_message(raw_connection);
248    let error_code = last_error_code(raw_connection);
249    let error_kind = match error_code {
250        ffi::SQLITE_CONSTRAINT_UNIQUE | ffi::SQLITE_CONSTRAINT_PRIMARYKEY => {
251            DatabaseErrorKind::UniqueViolation
252        }
253        ffi::SQLITE_CONSTRAINT_FOREIGNKEY => DatabaseErrorKind::ForeignKeyViolation,
254        // SQLITE_CONSTRAINT_TRIGGER is returned for ON DELETE RESTRICT violations,
255        // which are actually foreign key violations. We check the error message
256        // to distinguish from user-defined trigger failures.
257        ffi::SQLITE_CONSTRAINT_TRIGGER
258            if error_message.contains("FOREIGN KEY constraint failed") =>
259        {
260            DatabaseErrorKind::ForeignKeyViolation
261        }
262        ffi::SQLITE_CONSTRAINT_NOTNULL => DatabaseErrorKind::NotNullViolation,
263        ffi::SQLITE_CONSTRAINT_CHECK => DatabaseErrorKind::CheckViolation,
264        _ => DatabaseErrorKind::Unknown,
265    };
266    let error_information = Box::new(error_message);
267    DatabaseError(error_kind, error_information)
268}
269
270fn last_error_message(conn: *mut ffi::sqlite3) -> String {
271    let c_str = unsafe { CStr::from_ptr(ffi::sqlite3_errmsg(conn)) };
272    c_str.to_string_lossy().into_owned()
273}
274
275fn last_error_code(conn: *mut ffi::sqlite3) -> libc::c_int {
276    unsafe { ffi::sqlite3_extended_errcode(conn) }
277}
278
279impl Drop for Statement {
280    fn drop(&mut self) {
281        // An error only repeats the last failed step, which already returned it.
282        unsafe { ffi::sqlite3_finalize(self.inner_statement.as_ptr()) };
283    }
284}
285
286// A warning for future editors:
287// Changing this code to something "simpler" may
288// introduce undefined behaviour. Make sure you read
289// the following discussions for details about
290// the current version:
291//
292// * https://github.com/weiznich/diesel/pull/7
293// * https://users.rust-lang.org/t/code-review-for-unsafe-code-in-diesel/66798/
294// * https://github.com/rust-lang/unsafe-code-guidelines/issues/194
295struct BoundStatement<'stmt, 'query> {
296    statement: MaybeCached<'stmt, Statement>,
297    // we need to store the query here to ensure no one does
298    // drop it till the end of the statement
299    // We use a boxed queryfragment here just to erase the
300    // generic type, we use NonNull to communicate
301    // that this is a shared buffer
302    query: Option<NonNull<dyn QueryFragment<Sqlite> + 'query>>,
303    // we need to store any owned bind values separately, as they are not
304    // contained in the query itself. We use NonNull to
305    // communicate that this is a shared buffer
306    binds_to_free: Vec<(i32, Option<NonNull<[u8]>>)>,
307    instrumentation: &'stmt mut dyn Instrumentation,
308    has_error: bool,
309}
310
311impl<'stmt, 'query> BoundStatement<'stmt, 'query> {
312    fn bind<T>(
313        mut statement: MaybeCached<'stmt, Statement>,
314        query: T,
315        instrumentation: &'stmt mut dyn Instrumentation,
316    ) -> QueryResult<BoundStatement<'stmt, 'query>>
317    where
318        T: QueryFragment<Sqlite> + QueryId + 'query,
319    {
320        // Don't use a trait object here to prevent using a virtual function call
321        // For sqlite this can introduce a measurable overhead
322        // Query is boxed here to make sure it won't move in memory anymore, so any bind
323        // it could output would stay valid.
324        let query = Box::new(query);
325        // make sure to reset any previously left bindings
326        statement.reset();
327        statement.clear_bindings();
328
329        let mut bind_collector = SqliteBindCollector::new();
330        query.collect_binds(&mut bind_collector, &mut (), &Sqlite)?;
331
332        let SqliteBindCollector { binds } = bind_collector;
333        if statement.parameter_count() != binds.len() as u64 {
334            return Err(
335                crate::connection::statement_cache::invalid_prepared_statement_parameter_count(
336                    statement.parameter_count().try_into().unwrap_or(usize::MAX),
337                    binds.len(),
338                ),
339            );
340        }
341
342        let mut ret = BoundStatement {
343            statement,
344            query: None,
345            binds_to_free: Vec::new(),
346            instrumentation,
347            has_error: false,
348        };
349
350        ret.bind_buffers(binds)?;
351
352        let query = query as Box<dyn QueryFragment<Sqlite> + 'query>;
353        ret.query = NonNull::new(Box::into_raw(query));
354
355        Ok(ret)
356    }
357
358    // This is a separated function so that
359    // not the whole constructor is generic over the query type T.
360    // This hopefully prevents binary bloat.
361    fn bind_buffers(
362        &mut self,
363        binds: Vec<(SqliteBindValueRef<'_>, SqliteType)>,
364    ) -> QueryResult<()> {
365        // It is useful to preallocate `binds_to_free` because it
366        // - Guarantees that pushing inside it cannot panic, which guarantees the `Drop`
367        //   impl of `BoundStatement` will always re-`bind` as needed
368        // - Avoids reallocations
369        self.binds_to_free.reserve(
370            binds
371                .iter()
372                .filter(|&(b, _)| {
373                    #[allow(non_exhaustive_omitted_patterns)] match b {
    SqliteBindValueRef::BorrowedBinary(_) |
        SqliteBindValueRef::BorrowedString(_) | SqliteBindValueRef::String(_)
        | SqliteBindValueRef::Binary(_) => true,
    _ => false,
}matches!(
374                        b,
375                        SqliteBindValueRef::BorrowedBinary(_)
376                            | SqliteBindValueRef::BorrowedString(_)
377                            | SqliteBindValueRef::String(_)
378                            | SqliteBindValueRef::Binary(_)
379                    )
380                })
381                .count(),
382        );
383        for (bind_idx, (bind, tpe)) in (1..).zip(binds) {
384            let is_borrowed_bind = #[allow(non_exhaustive_omitted_patterns)] match bind {
    SqliteBindValueRef::BorrowedString(_) |
        SqliteBindValueRef::BorrowedBinary(_) => true,
    _ => false,
}matches!(
385                bind,
386                SqliteBindValueRef::BorrowedString(_) | SqliteBindValueRef::BorrowedBinary(_)
387            );
388
389            // It's safe to call bind here as:
390            // * The type and value matches
391            // * We ensure that corresponding buffers lives long enough below
392            // * The statement is not used yet by `step` or anything else
393            let res = unsafe { self.statement.bind(tpe, bind, bind_idx) }?;
394
395            // it's important to push these only after
396            // the call to bind succeeded, otherwise we might attempt to
397            // call bind to an non-existing bind position in
398            // the destructor
399            if let Some(ptr) = res {
400                // Store the id + pointer for a owned bind
401                // as we must unbind and free them on drop
402                self.binds_to_free.push((bind_idx, Some(ptr)));
403            } else if is_borrowed_bind {
404                // Store the id's of borrowed binds to unbind them on drop
405                self.binds_to_free.push((bind_idx, None));
406            }
407        }
408        Ok(())
409    }
410
411    fn finish_query_with_error(mut self, e: &Error) {
412        self.has_error = true;
413        if let Some(q) = self.query {
414            // it's safe to get a reference from this ptr as it's guaranteed to not be null
415            let q = unsafe { q.as_ref() };
416            self.instrumentation.on_connection_event(
417                crate::connection::InstrumentationEvent::FinishQuery {
418                    query: &crate::debug_query(&q),
419                    error: Some(e),
420                },
421            );
422        }
423    }
424}
425
426impl Drop for BoundStatement<'_, '_> {
427    fn drop(&mut self) {
428        // First reset the statement, otherwise the bind calls
429        // below will fails
430        self.statement.reset();
431
432        for (idx, buffer) in core::mem::take(&mut self.binds_to_free) {
433            unsafe {
434                // It's always safe to bind null values, as there is no buffer that needs to outlife something
435                self.statement
436                    .bind(SqliteType::Text, SqliteBindValueRef::Null, idx)
437                    .expect(
438                        "Binding a null value should never fail. \
439                             If you ever see this error message please open \
440                             an issue at diesels issue tracker containing \
441                             code how to trigger this message.",
442                    );
443            }
444
445            if let Some(buffer) = buffer {
446                unsafe {
447                    // Constructing the `Box` here is safe as we
448                    // got the pointer from a box + it is guaranteed to be not null.
449                    core::mem::drop(Box::from_raw(buffer.as_ptr()));
450                }
451            }
452        }
453
454        if let Some(query) = self.query {
455            let query = unsafe {
456                // Constructing the `Box` here is safe as we
457                // got the pointer from a box + it is guaranteed to be not null.
458                Box::from_raw(query.as_ptr())
459            };
460            if !self.has_error {
461                self.instrumentation.on_connection_event(
462                    crate::connection::InstrumentationEvent::FinishQuery {
463                        query: &crate::debug_query(&query),
464                        error: None,
465                    },
466                );
467            }
468            core::mem::drop(query);
469            self.query = None;
470        }
471    }
472}
473
474#[allow(missing_debug_implementations)]
475pub struct StatementUse<'stmt, 'query> {
476    statement: BoundStatement<'stmt, 'query>,
477    // SAFETY:
478    // https://sqlite.org/c3ref/column_name.html
479    // This pointer is valid as long as:
480    // The returned string pointer is valid until either
481    // the prepared statement is destroyed by sqlite3_finalize()
482    // or until the statement is automatically reprepared by the first
483    // call to sqlite3_step() for a particular run or until the next call
484    // to sqlite3_column_name() or sqlite3_column_name16() on the same column.
485    //
486    // Step has an explicit `first` flag that resets this field
487    // in this case
488    // The `OnceCell` ensure that we never call
489    // `sqlite3_column_name` again after populating this field
490    //
491    // We also assume that we are the owner of `statement` and the
492    // inner pointer is not exposed anywhere else. This ensures
493    // no one else can call the functions mentioned above
494    //
495    // We use `*const str` instead of `&str`
496    // as this is essentially a self referential struct
497    // as we borrow into `statement`
498    column_names: OnceCell<Vec<*const str>>,
499}
500
501impl<'stmt, 'query> StatementUse<'stmt, 'query> {
502    pub(super) fn bind<T>(
503        statement: MaybeCached<'stmt, Statement>,
504        query: T,
505        instrumentation: &'stmt mut dyn Instrumentation,
506    ) -> QueryResult<StatementUse<'stmt, 'query>>
507    where
508        T: QueryFragment<Sqlite> + QueryId + 'query,
509    {
510        Ok(Self {
511            statement: BoundStatement::bind(statement, query, instrumentation)?,
512            column_names: OnceCell::new(),
513        })
514    }
515
516    pub(super) fn run(mut self) -> QueryResult<()> {
517        let r = unsafe {
518            // This is safe as we pass `first_step = true`
519            // and we consume the statement so nobody could
520            // access the columns later on anyway.
521            self.step(true).map(|_| ())
522        };
523        if let Err(ref e) = r {
524            self.statement.finish_query_with_error(e);
525        }
526        r
527    }
528
529    // This function is marked as unsafe incorrectly passing `false` to `first_step`
530    // for a first call to this function could cause access to freed memory via
531    // the cached column names.
532    //
533    // It's always safe to call this function with `first_step = true` as this removes
534    // the cached column names
535    pub(super) unsafe fn step(&mut self, first_step: bool) -> QueryResult<bool> {
536        let step_result =
537            unsafe { ffi::sqlite3_step(self.statement.statement.inner_statement.as_ptr()) };
538        let res = match step_result {
539            ffi::SQLITE_DONE => Ok(false),
540            ffi::SQLITE_ROW => Ok(true),
541            _ => Err(last_error(self.statement.statement.raw_connection())),
542        };
543        if first_step {
544            self.column_names = OnceCell::new();
545        }
546        res
547    }
548
549    // The returned string pointer is valid until either the prepared statement is
550    // destroyed by sqlite3_finalize() or until the statement is automatically
551    // reprepared by the first call to sqlite3_step() for a particular run or
552    // until the next call to sqlite3_column_name() or sqlite3_column_name16()
553    // on the same column.
554    //
555    // https://sqlite.org/c3ref/column_name.html
556    //
557    // Note: This function is marked as unsafe, as calling it can invalidate
558    // other existing column name pointers on the same column. To prevent that,
559    // it should maximally be called once per column at all.
560    unsafe fn column_name(&self, idx: i32) -> *const str {
561        let name = {
562            let column_name = unsafe {
563                ffi::sqlite3_column_name(self.statement.statement.inner_statement.as_ptr(), idx)
564            };
565            if !!column_name.is_null() {
    {
        ::core::panicking::panic_fmt(format_args!("The Sqlite documentation states that it only returns a null pointer here if we are in a OOM condition."));
    }
};assert!(
566                !column_name.is_null(),
567                "The Sqlite documentation states that it only returns a \
568                 null pointer here if we are in a OOM condition."
569            );
570            unsafe { CStr::from_ptr(column_name) }
571        };
572        name.to_str().expect(
573            "The Sqlite documentation states that this is UTF8. \
574             If you see this error message something has gone \
575             horribly wrong. Please open an issue at the \
576             diesel repository.",
577        ) as *const str
578    }
579
580    pub(super) fn column_count(&self) -> i32 {
581        unsafe { ffi::sqlite3_column_count(self.statement.statement.inner_statement.as_ptr()) }
582    }
583
584    pub(super) fn index_for_column_name(&mut self, field_name: &str) -> Option<usize> {
585        (0..self.column_count())
586            .find(|idx| self.field_name(*idx) == Some(field_name))
587            .map(|v| {
588                v.try_into()
589                    .expect("Diesel expects to run at least on a 32 bit platform")
590            })
591    }
592
593    pub(super) fn field_name(&self, idx: i32) -> Option<&str> {
594        let column_names = self.column_names.get_or_init(|| {
595            let count = self.column_count();
596            (0..count)
597                .map(|idx| unsafe {
598                    // By initializing the whole vec at once we ensure that
599                    // we really call this only once.
600                    self.column_name(idx)
601                })
602                .collect()
603        });
604
605        column_names
606            .get(usize::try_from(idx).expect("Diesel expects to run at least on a 32 bit platform"))
607            .and_then(|c| unsafe { c.as_ref() })
608    }
609
610    pub(super) fn copy_value(&self, idx: i32) -> QueryResult<Option<OwnedSqliteValue>> {
611        match self.column_value(idx) {
612            Some(ptr) => OwnedSqliteValue::copy_from_ptr(ptr),
613            None => Ok(None),
614        }
615    }
616
617    pub(super) fn column_value(&self, idx: i32) -> Option<NonNull<ffi::sqlite3_value>> {
618        let ptr = unsafe {
619            ffi::sqlite3_column_value(self.statement.statement.inner_statement.as_ptr(), idx)
620        };
621        NonNull::new(ptr)
622    }
623
624    pub(super) fn raw_connection(&self) -> *mut ffi::sqlite3 {
625        self.statement.statement.raw_connection()
626    }
627}
628
629#[cfg(test)]
630mod tests {
631    #[cfg(not(miri))]
632    use crate::prelude::*;
633    #[cfg(not(miri))]
634    use crate::sql_types::Text;
635
636    // this is a regression test for
637    // https://github.com/diesel-rs/diesel/issues/3558
638    //
639    // Reading sqlite's error message requires accessing memory allocated by
640    // the native library, which is not supported when running under miri with
641    // a native libsqlite3 (`-Zmiri-native-lib`).
642    #[cfg(not(miri))] // ffi call
643    #[diesel_test_helper::test]
644    fn check_out_of_bounds_bind_does_not_panic_on_drop() {
645        let mut conn = SqliteConnection::establish(":memory:").unwrap();
646
647        let e = crate::sql_query("SELECT '?'")
648            .bind::<Text, _>("foo")
649            .execute(&mut conn);
650
651        assert!(e.is_err());
652        let e = e.unwrap_err();
653        assert_eq!(
654            e.to_string(),
655            "prepared statement expected a different number of parameters than provided: Expected 0, provided: 1"
656        );
657    }
658}