Skip to main content

rusqlite/
lib.rs

1//! Rusqlite is an ergonomic wrapper for using SQLite from Rust.
2//!
3//! Historically, the API was based on the one from
4//! [`rust-postgres`](https://github.com/sfackler/rust-postgres). However, the
5//! two have diverged in many ways, and no compatibility between the two is
6//! intended.
7//!
8//! ```rust
9//! use rusqlite::{Connection, Result, params};
10//!
11//! #[derive(Debug)]
12//! struct Person {
13//!     id: i32,
14//!     name: String,
15//!     data: Option<Vec<u8>>,
16//! }
17//!
18//! fn main() -> Result<()> {
19//!     let conn = Connection::open_in_memory()?;
20//!
21//!     conn.execute(
22//!         "CREATE TABLE person (
23//!             id   INTEGER PRIMARY KEY,
24//!             name TEXT NOT NULL,
25//!             data BLOB
26//!         )",
27//!         (), // empty list of parameters.
28//!     )?;
29//!     let me = Person {
30//!         id: 0,
31//!         name: "Steven".to_string(),
32//!         data: None,
33//!     };
34//!     conn.execute(
35//!         "INSERT INTO person (name, data) VALUES (?1, ?2)",
36//!         (&me.name, &me.data),
37//!     )?;
38//!
39//!     let mut stmt = conn.prepare("SELECT id, name, data FROM person")?;
40//!     let person_iter = stmt.query_map([], |row| {
41//!         Ok(Person {
42//!             id: row.get(0)?,
43//!             name: row.get(1)?,
44//!             data: row.get(2)?,
45//!         })
46//!     })?;
47//!
48//!     for person in person_iter {
49//!         println!("Found person {:?}", person?);
50//!     }
51//!     Ok(())
52//! }
53//! ```
54#![warn(missing_docs)]
55#![cfg_attr(docsrs, feature(doc_cfg))]
56
57pub use fallible_iterator;
58pub use fallible_streaming_iterator;
59
60#[cfg(not(all(
61    target_family = "wasm",
62    target_os = "unknown",
63    any(test, feature = "ffi-sqlite-wasm-rs")
64)))]
65pub use libsqlite3_sys as ffi;
66#[cfg(all(
67    target_family = "wasm",
68    target_os = "unknown",
69    any(test, feature = "ffi-sqlite-wasm-rs")
70))]
71pub use sqlite_wasm_rs as ffi;
72
73use std::cell::RefCell;
74use std::default::Default;
75use std::ffi::{CStr, CString, c_char, c_int, c_uint, c_void};
76use std::fmt;
77
78use std::path::Path;
79use std::result;
80use std::str;
81use std::sync::{Arc, Mutex};
82
83#[cfg(feature = "cache")]
84use crate::cache::StatementCache;
85use crate::inner_connection::InnerConnection;
86use crate::raw_statement::RawStatement;
87use crate::types::ValueRef;
88
89pub use crate::bind::BindIndex;
90#[cfg(feature = "cache")]
91pub use crate::cache::CachedStatement;
92#[cfg(feature = "column_decltype")]
93pub use crate::column::Column;
94#[cfg(feature = "column_metadata")]
95pub use crate::column::ColumnMetadata;
96pub use crate::error::{Error, to_sqlite_error};
97pub use crate::ffi::ErrorCode;
98#[cfg(feature = "load_extension")]
99pub use crate::load_extension_guard::LoadExtensionGuard;
100pub use crate::params::{Params, ParamsFromIter, params_from_iter};
101pub use crate::row::{AndThenRows, Map, MappedRows, Row, RowIndex, Rows};
102pub use crate::statement::{Statement, StatementStatus};
103pub use crate::transaction::TransactionState;
104pub use crate::transaction::{DropBehavior, Savepoint, Transaction, TransactionBehavior};
105pub use crate::types::ToSql;
106pub use crate::util::Name;
107pub use crate::version::*;
108#[cfg(feature = "rusqlite-macros")]
109#[doc(hidden)]
110pub use rusqlite_macros::__bind;
111
112#[macro_use]
113mod error;
114
115#[cfg(not(feature = "loadable_extension"))]
116pub mod auto_extension;
117#[cfg(feature = "backup")]
118pub mod backup;
119mod bind;
120#[cfg(feature = "blob")]
121pub mod blob;
122mod busy;
123#[cfg(feature = "cache")]
124mod cache;
125#[cfg(feature = "collation")]
126mod collation;
127mod column;
128pub mod config;
129#[cfg(any(feature = "functions", feature = "vtab"))]
130mod context;
131#[cfg(feature = "functions")]
132pub mod functions;
133#[cfg(feature = "hooks")]
134pub mod hooks;
135mod inner_connection;
136#[cfg(feature = "limits")]
137pub mod limits;
138#[cfg(feature = "load_extension")]
139mod load_extension_guard;
140mod params;
141mod pragma;
142mod raw_statement;
143mod row;
144#[cfg(feature = "serialize")]
145pub mod serialize;
146#[cfg(feature = "session")]
147pub mod session;
148mod statement;
149#[cfg(feature = "trace")]
150pub mod trace;
151mod transaction;
152pub mod types;
153#[cfg(feature = "unlock_notify")]
154mod unlock_notify;
155mod version;
156#[cfg(feature = "vtab")]
157pub mod vtab;
158
159pub(crate) mod util;
160#[cfg(feature = "wal")]
161pub mod wal;
162
163// Actually, only sqlite3_enable_load_extension is disabled (not sqlite3_load_extension)
164#[cfg(all(feature = "loadable_extension", feature = "load_extension"))]
165compile_error!(
166    "feature \"loadable_extension\" and feature \"load_extension\" cannot be enabled at the same time"
167);
168
169// Number of cached prepared statements we'll hold on to.
170#[cfg(feature = "cache")]
171const STATEMENT_CACHE_DEFAULT_CAPACITY: usize = 16;
172
173/// A macro making it more convenient to pass longer lists of
174/// parameters as a `&[&dyn ToSql]`.
175///
176/// # Example
177///
178/// ```rust,no_run
179/// # use rusqlite::{Result, Connection, params};
180///
181/// struct Person {
182///     name: String,
183///     age_in_years: u8,
184///     data: Option<Vec<u8>>,
185/// }
186///
187/// fn add_person(conn: &Connection, person: &Person) -> Result<()> {
188///     conn.execute(
189///         "INSERT INTO person(name, age_in_years, data) VALUES (?1, ?2, ?3)",
190///         params![person.name, person.age_in_years, person.data],
191///     )?;
192///     Ok(())
193/// }
194/// ```
195#[macro_export]
196macro_rules! params {
197    () => {
198        &[] as &[&dyn $crate::ToSql]
199    };
200    ($($param:expr),+ $(,)?) => {
201        &[$(&$param as &dyn $crate::ToSql),+] as &[&dyn $crate::ToSql]
202    };
203}
204
205/// A macro making it more convenient to pass lists of named parameters
206/// as a `&[(&str, &dyn ToSql)]`.
207///
208/// # Example
209///
210/// ```rust,no_run
211/// # use rusqlite::{Result, Connection, named_params};
212///
213/// struct Person {
214///     name: String,
215///     age_in_years: u8,
216///     data: Option<Vec<u8>>,
217/// }
218///
219/// fn add_person(conn: &Connection, person: &Person) -> Result<()> {
220///     conn.execute(
221///         "INSERT INTO person (name, age_in_years, data)
222///          VALUES (:name, :age, :data)",
223///         named_params! {
224///             ":name": person.name,
225///             ":age": person.age_in_years,
226///             ":data": person.data,
227///         },
228///     )?;
229///     Ok(())
230/// }
231/// ```
232#[macro_export]
233macro_rules! named_params {
234    () => {
235        &[] as &[(&str, &dyn $crate::ToSql)]
236    };
237    // Note: It's a lot more work to support this as part of the same macro as
238    // `params!`, unfortunately.
239    ($($param_name:literal: $param_val:expr),+ $(,)?) => {
240        &[$(($param_name, &$param_val as &dyn $crate::ToSql)),+] as &[(&str, &dyn $crate::ToSql)]
241    };
242}
243
244/// Captured identifiers in SQL
245///
246/// * only SQLite `$x` / `@x` / `:x` syntax works (Rust `&x` syntax does not
247///   work).
248/// * `$x.y` expression does not work.
249///
250/// # Example
251///
252/// ```rust, no_run
253/// # use rusqlite::{prepare_and_bind, Connection, Result, Statement};
254///
255/// fn misc(db: &Connection) -> Result<Statement> {
256///     let name = "Lisa";
257///     let age = 8;
258///     let smart = true;
259///     Ok(prepare_and_bind!(db, "SELECT $name, @age, :smart;"))
260/// }
261/// ```
262#[cfg(feature = "rusqlite-macros")]
263#[macro_export]
264macro_rules! prepare_and_bind {
265    ($conn:expr, $sql:literal) => {{
266        let mut stmt = $conn.prepare($sql)?;
267        $crate::__bind!(stmt $sql);
268        stmt
269    }};
270}
271
272/// Captured identifiers in SQL
273///
274/// * only SQLite `$x` / `@x` / `:x` syntax works (Rust `&x` syntax does not
275///   work).
276/// * `$x.y` expression does not work.
277#[cfg(feature = "rusqlite-macros")]
278#[macro_export]
279macro_rules! prepare_cached_and_bind {
280    ($conn:expr, $sql:literal) => {{
281        let mut stmt = $conn.prepare_cached($sql)?;
282        $crate::__bind!(stmt $sql);
283        stmt
284    }};
285}
286
287/// A typedef of the result returned by many methods.
288pub type Result<T, E = Error> = result::Result<T, E>;
289
290/// See the [method documentation](#tymethod.optional).
291pub trait OptionalExtension<T> {
292    /// Converts a `Result<T>` into a `Result<Option<T>>`.
293    ///
294    /// By default, Rusqlite treats 0 rows being returned from a query that is
295    /// expected to return 1 row as an error. This method will
296    /// handle that error, and give you back an `Option<T>` instead.
297    fn optional(self) -> Result<Option<T>>;
298}
299
300impl<T> OptionalExtension<T> for Result<T> {
301    fn optional(self) -> Result<Option<T>> {
302        match self {
303            Ok(value) => Ok(Some(value)),
304            Err(Error::QueryReturnedNoRows) => Ok(None),
305            Err(e) => Err(e),
306        }
307    }
308}
309
310unsafe fn errmsg_to_string(errmsg: *const c_char) -> String {
311    unsafe { CStr::from_ptr(errmsg) }
312        .to_string_lossy()
313        .into_owned()
314}
315
316#[cfg(any(feature = "functions", feature = "vtab", test))]
317fn str_to_cstring(s: &str) -> Result<util::SmallCString> {
318    Ok(util::SmallCString::new(s)?)
319}
320
321/// Returns `(string ptr, len as c_int, SQLITE_STATIC | SQLITE_TRANSIENT)`
322/// normally.
323/// The `sqlite3_destructor_type` item is always `SQLITE_TRANSIENT` unless
324/// the string was empty (in which case it's `SQLITE_STATIC`, and the ptr is
325/// static).
326fn str_for_sqlite(
327    s: &[u8],
328) -> (
329    *const c_char,
330    ffi::sqlite3_uint64,
331    ffi::sqlite3_destructor_type,
332) {
333    let len = s.len();
334    let (ptr, dtor_info) = if len != 0 {
335        (s.as_ptr().cast::<c_char>(), ffi::SQLITE_TRANSIENT())
336    } else {
337        // Return a pointer guaranteed to live forever
338        ("".as_ptr().cast::<c_char>(), ffi::SQLITE_STATIC())
339    };
340    (ptr, len as ffi::sqlite3_uint64, dtor_info)
341}
342
343fn path_to_cstring(p: &Path) -> Result<CString> {
344    cfg_select! {
345        unix => {
346            use std::os::unix::ffi::OsStrExt as _;
347            Ok(CString::new(p.as_os_str().as_bytes())?)
348        }
349        _ => {
350            let s = p.to_str().ok_or_else(|| Error::InvalidPath(p.to_owned()))?;
351            Ok(CString::new(s)?)
352        }
353    }
354}
355
356/// Shorthand for `Main` database.
357pub const MAIN_DB: &CStr = c"main";
358/// Shorthand for default name.
359pub const DEFAULT_NAME: Option<&'static str> = None;
360/// Shorthand for `Temp` database.
361pub const TEMP_DB: &CStr = c"temp";
362
363/// A connection to a SQLite database.
364pub struct Connection {
365    db: RefCell<InnerConnection>,
366    #[cfg(feature = "cache")]
367    cache: StatementCache,
368    transaction_behavior: TransactionBehavior,
369}
370
371unsafe impl Send for Connection {}
372
373impl Drop for Connection {
374    #[inline]
375    fn drop(&mut self) {
376        #[cfg(feature = "cache")]
377        self.flush_prepared_statement_cache();
378    }
379}
380
381impl Connection {
382    /// Open a new connection to a SQLite database. If a database does not exist
383    /// at the path, one is created.
384    ///
385    /// ```rust,no_run
386    /// # use rusqlite::{Connection, Result};
387    /// fn open_my_db() -> Result<()> {
388    ///     let path = "./my_db.db3";
389    ///     let db = Connection::open(path)?;
390    ///     // Use the database somehow...
391    ///     println!("{}", db.is_autocommit());
392    ///     Ok(())
393    /// }
394    /// ```
395    ///
396    /// # Flags
397    ///
398    /// `Connection::open(path)` is equivalent to using
399    /// [`Connection::open_with_flags`] with the default [`OpenFlags`]. That is,
400    /// it's equivalent to:
401    ///
402    /// ```ignore
403    /// Connection::open_with_flags(
404    ///     path,
405    ///     OpenFlags::SQLITE_OPEN_READ_WRITE
406    ///         | OpenFlags::SQLITE_OPEN_CREATE
407    ///         | OpenFlags::SQLITE_OPEN_URI
408    ///         | OpenFlags::SQLITE_OPEN_NO_MUTEX,
409    /// )
410    /// ```
411    ///
412    /// These flags have the following effects:
413    ///
414    /// - Open the database for both reading or writing.
415    /// - Create the database if one does not exist at the path.
416    /// - Allow the filename to be interpreted as a URI (see <https://www.sqlite.org/uri.html#uri_filenames_in_sqlite>
417    ///   for details).
418    /// - Disables the use of a per-connection mutex.
419    ///
420    ///   Rusqlite enforces thread-safety at compile time, so additional
421    ///   locking is not needed and provides no benefit. (See the
422    ///   documentation on [`OpenFlags::SQLITE_OPEN_FULL_MUTEX`] for some
423    ///   additional discussion about this).
424    ///
425    /// Most of these are also the default settings for the C API, although
426    /// technically the default locking behavior is controlled by the flags used
427    /// when compiling SQLite -- rather than let it vary, we choose `NO_MUTEX`
428    /// because it's a fairly clearly the best choice for users of this library.
429    ///
430    /// # Failure
431    ///
432    /// Will return `Err` if `path` cannot be converted to a C-compatible string
433    /// or if the underlying SQLite open call fails.
434    ///
435    /// # WASM support
436    ///
437    /// If you plan to use this connection type on the `wasm32-unknown-unknown` target please
438    /// make sure to read the following notes:
439    ///
440    /// - The database is stored in memory by default.
441    /// * With `sqlite-wasm-rs` 0.6, enable its `wasm-bindgen` feature to use the
442    ///   built-in host functions, or provide your own.
443    /// - Persistent VFS (Virtual File Systems) is optional,
444    ///   see <https://github.com/Spxg/sqlite-wasm-rs> for details
445    #[inline]
446    pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
447        let flags = OpenFlags::default();
448        Self::open_with_flags(path, flags)
449    }
450
451    /// Open a new connection to an in-memory SQLite database.
452    ///
453    /// # Failure
454    ///
455    /// Will return `Err` if the underlying SQLite open call fails.
456    #[inline]
457    pub fn open_in_memory() -> Result<Self> {
458        let flags = OpenFlags::default();
459        Self::open_in_memory_with_flags(flags)
460    }
461
462    /// Open a new connection to a SQLite database.
463    ///
464    /// [Database Connection](http://www.sqlite.org/c3ref/open.html) for a description of valid
465    /// flag combinations.
466    ///
467    /// # Failure
468    ///
469    /// Will return `Err` if `path` cannot be converted to a C-compatible
470    /// string or if the underlying SQLite open call fails.
471    #[inline]
472    pub fn open_with_flags<P: AsRef<Path>>(path: P, flags: OpenFlags) -> Result<Self> {
473        let c_path = path_to_cstring(path.as_ref())?;
474        InnerConnection::open_with_flags(&c_path, flags, None).map(|db| Self {
475            db: RefCell::new(db),
476            #[cfg(feature = "cache")]
477            cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
478            transaction_behavior: TransactionBehavior::Deferred,
479        })
480    }
481
482    /// Open a new connection to a SQLite database using the specific flags and
483    /// vfs name.
484    ///
485    /// [Database Connection](http://www.sqlite.org/c3ref/open.html) for a description of valid
486    /// flag combinations.
487    ///
488    /// # Failure
489    ///
490    /// Will return `Err` if either `path` or `vfs` cannot be converted to a
491    /// C-compatible string or if the underlying SQLite open call fails.
492    #[inline]
493    pub fn open_with_flags_and_vfs<P: AsRef<Path>, V: Name>(
494        path: P,
495        flags: OpenFlags,
496        vfs: V,
497    ) -> Result<Self> {
498        let c_path = path_to_cstring(path.as_ref())?;
499        let c_vfs = vfs.as_cstr()?;
500        InnerConnection::open_with_flags(&c_path, flags, Some(&c_vfs)).map(|db| Self {
501            db: RefCell::new(db),
502            #[cfg(feature = "cache")]
503            cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
504            transaction_behavior: TransactionBehavior::Deferred,
505        })
506    }
507
508    /// Open a new connection to an in-memory SQLite database.
509    ///
510    /// [Database Connection](http://www.sqlite.org/c3ref/open.html) for a description of valid
511    /// flag combinations.
512    ///
513    /// # Failure
514    ///
515    /// Will return `Err` if the underlying SQLite open call fails.
516    #[inline]
517    pub fn open_in_memory_with_flags(flags: OpenFlags) -> Result<Self> {
518        Self::open_with_flags(":memory:", flags)
519    }
520
521    /// Open a new connection to an in-memory SQLite database using the specific
522    /// flags and vfs name.
523    ///
524    /// [Database Connection](http://www.sqlite.org/c3ref/open.html) for a description of valid
525    /// flag combinations.
526    ///
527    /// # Failure
528    ///
529    /// Will return `Err` if `vfs` cannot be converted to a C-compatible
530    /// string or if the underlying SQLite open call fails.
531    #[inline]
532    pub fn open_in_memory_with_flags_and_vfs<V: Name>(flags: OpenFlags, vfs: V) -> Result<Self> {
533        Self::open_with_flags_and_vfs(":memory:", flags, vfs)
534    }
535
536    /// Convenience method to run multiple SQL statements (that cannot take any
537    /// parameters).
538    ///
539    /// ## Example
540    ///
541    /// ```rust,no_run
542    /// # use rusqlite::{Connection, Result};
543    /// fn create_tables(conn: &Connection) -> Result<()> {
544    ///     conn.execute_batch(
545    ///         "BEGIN;
546    ///          CREATE TABLE foo(x INTEGER);
547    ///          CREATE TABLE bar(y TEXT);
548    ///          COMMIT;",
549    ///     )
550    /// }
551    /// ```
552    ///
553    /// # Failure
554    ///
555    /// Will return `Err` if `sql` cannot be converted to a C-compatible string
556    /// or if the underlying SQLite call fails.
557    pub fn execute_batch(&self, sql: &str) -> Result<()> {
558        let mut sql = sql;
559        while !sql.is_empty() {
560            let (stmt, tail) = self
561                .db
562                .borrow_mut()
563                .prepare(self, sql, PrepFlags::default())?;
564            if !stmt.stmt.is_null() && stmt.step()? {
565                // Some PRAGMA may return rows
566                if false {
567                    return Err(Error::ExecuteReturnedResults);
568                }
569            }
570            if tail == 0 || tail >= sql.len() {
571                break;
572            }
573            sql = &sql[tail..];
574        }
575        Ok(())
576    }
577
578    /// Convenience method to prepare and execute a single SQL statement.
579    ///
580    /// On success, returns the number of rows that were changed or inserted or
581    /// deleted (via `sqlite3_changes`).
582    ///
583    /// ## Example
584    ///
585    /// ### With positional params
586    ///
587    /// ```rust,no_run
588    /// # use rusqlite::{Connection};
589    /// fn update_rows(conn: &Connection) {
590    ///     match conn.execute("UPDATE foo SET bar = 'baz' WHERE qux = ?1", [1i32]) {
591    ///         Ok(updated) => println!("{} rows were updated", updated),
592    ///         Err(err) => println!("update failed: {}", err),
593    ///     }
594    /// }
595    /// ```
596    ///
597    /// ### With positional params of varying types
598    ///
599    /// ```rust,no_run
600    /// # use rusqlite::{params, Connection};
601    /// fn update_rows(conn: &Connection) {
602    ///     match conn.execute(
603    ///         "UPDATE foo SET bar = 'baz' WHERE qux = ?1 AND quux = ?2",
604    ///         params![1i32, 1.5f64],
605    ///     ) {
606    ///         Ok(updated) => println!("{} rows were updated", updated),
607    ///         Err(err) => println!("update failed: {}", err),
608    ///     }
609    /// }
610    /// ```
611    ///
612    /// ### With named params
613    ///
614    /// ```rust,no_run
615    /// # use rusqlite::{Connection, Result};
616    /// fn insert(conn: &Connection) -> Result<usize> {
617    ///     conn.execute(
618    ///         "INSERT INTO test (name) VALUES (:name)",
619    ///         &[(":name", "one")],
620    ///     )
621    /// }
622    /// ```
623    ///
624    /// # Failure
625    ///
626    /// Will return `Err` if `sql` cannot be converted to a C-compatible string
627    /// or if the underlying SQLite call fails.
628    #[inline]
629    pub fn execute<P: Params>(&self, sql: &str, params: P) -> Result<usize> {
630        self.prepare(sql).and_then(|mut stmt| stmt.execute(params))
631    }
632
633    /// Returns the path to the database file, if one exists and is known.
634    ///
635    /// Returns `Some("")` for a temporary or in-memory database.
636    ///
637    /// Note that in some cases [PRAGMA
638    /// database_list](https://sqlite.org/pragma.html#pragma_database_list) is
639    /// likely to be more robust.
640    #[inline]
641    pub fn path(&self) -> Option<&str> {
642        unsafe { inner_connection::db_filename(std::marker::PhantomData, self.handle(), MAIN_DB) }
643    }
644
645    /// Attempts to free as much heap memory as possible from the database
646    /// connection.
647    ///
648    /// This calls [`sqlite3_db_release_memory`](https://www.sqlite.org/c3ref/db_release_memory.html).
649    #[inline]
650    pub fn release_memory(&self) -> Result<()> {
651        self.db.borrow_mut().release_memory()
652    }
653
654    /// Get the SQLite rowid of the most recent successful INSERT.
655    ///
656    /// Uses [sqlite3_last_insert_rowid](https://www.sqlite.org/c3ref/last_insert_rowid.html) under
657    /// the hood.
658    #[inline]
659    pub fn last_insert_rowid(&self) -> i64 {
660        self.db.borrow_mut().last_insert_rowid()
661    }
662
663    /// Convenience method to execute a query that is expected to return a
664    /// single row.
665    ///
666    /// ## Example
667    ///
668    /// ```rust,no_run
669    /// # use rusqlite::{Result, Connection};
670    /// fn preferred_locale(conn: &Connection) -> Result<String> {
671    ///     conn.query_row(
672    ///         "SELECT value FROM preferences WHERE name='locale'",
673    ///         [],
674    ///         |row| row.get(0),
675    ///     )
676    /// }
677    /// ```
678    ///
679    /// If the query returns more than one row, all rows except the first are
680    /// ignored.
681    ///
682    /// Returns `Err(QueryReturnedNoRows)` if no results are returned. If the
683    /// query truly is optional, you can call `.optional()` on the result of
684    /// this to get a `Result<Option<T>>`.
685    ///
686    /// # Failure
687    ///
688    /// Will return `Err` if `sql` cannot be converted to a C-compatible string
689    /// or if the underlying SQLite call fails.
690    #[inline]
691    pub fn query_row<T, P, F>(&self, sql: &str, params: P, f: F) -> Result<T>
692    where
693        P: Params,
694        F: FnOnce(&Row<'_>) -> Result<T>,
695    {
696        let mut stmt = self.prepare(sql)?;
697        stmt.query_row(params, f)
698    }
699
700    /// Convenience method to execute a query that is expected to return exactly
701    /// one row.
702    ///
703    /// Returns `Err(QueryReturnedMoreThanOneRow)` if the query returns more than one row.
704    ///
705    /// Returns `Err(QueryReturnedNoRows)` if no results are returned. If the
706    /// query truly is optional, you can call
707    /// [`.optional()`](OptionalExtension::optional) on the result of
708    /// this to get a `Result<Option<T>>` (requires that the trait
709    /// `rusqlite::OptionalExtension` is imported).
710    ///
711    /// # Failure
712    ///
713    /// Will return `Err` if the underlying SQLite call fails.
714    pub fn query_one<T, P, F>(&self, sql: &str, params: P, f: F) -> Result<T>
715    where
716        P: Params,
717        F: FnOnce(&Row<'_>) -> Result<T>,
718    {
719        let mut stmt = self.prepare(sql)?;
720        stmt.query_one(params, f)
721    }
722
723    // https://sqlite.org/tclsqlite.html#onecolumn
724    pub(crate) fn one_column<T, P>(&self, sql: &str, params: P) -> Result<T>
725    where
726        T: types::FromSql,
727        P: Params,
728    {
729        self.query_one(sql, params, |r| r.get(0))
730    }
731
732    /// Convenience method to execute a query that is expected to return a
733    /// single row, and execute a mapping via `f` on that returned row with
734    /// the possibility of failure. The `Result` type of `f` must implement
735    /// `std::convert::From<Error>`.
736    ///
737    /// ## Example
738    ///
739    /// ```rust,no_run
740    /// # use rusqlite::{Result, Connection};
741    /// fn preferred_locale(conn: &Connection) -> Result<String> {
742    ///     conn.query_row_and_then(
743    ///         "SELECT value FROM preferences WHERE name='locale'",
744    ///         [],
745    ///         |row| row.get(0),
746    ///     )
747    /// }
748    /// ```
749    ///
750    /// If the query returns more than one row, all rows except the first are
751    /// ignored.
752    ///
753    /// # Failure
754    ///
755    /// Will return `Err` if `sql` cannot be converted to a C-compatible string
756    /// or if the underlying SQLite call fails.
757    #[inline]
758    pub fn query_row_and_then<T, E, P, F>(&self, sql: &str, params: P, f: F) -> Result<T, E>
759    where
760        P: Params,
761        F: FnOnce(&Row<'_>) -> Result<T, E>,
762        E: From<Error>,
763    {
764        let mut stmt = self.prepare(sql)?;
765        let mut rows = stmt.query(params)?;
766
767        rows.get_expected_row().map_err(E::from).and_then(f)
768    }
769
770    /// Prepare a SQL statement for execution.
771    ///
772    /// ## Example
773    ///
774    /// ```rust,no_run
775    /// # use rusqlite::{Connection, Result};
776    /// fn insert_new_people(conn: &Connection) -> Result<()> {
777    ///     let mut stmt = conn.prepare("INSERT INTO People (name) VALUES (?1)")?;
778    ///     stmt.execute(["Joe Smith"])?;
779    ///     stmt.execute(["Bob Jones"])?;
780    ///     Ok(())
781    /// }
782    /// ```
783    ///
784    /// # Failure
785    ///
786    /// Will return `Err` if `sql` cannot be converted to a C-compatible string
787    /// or if the underlying SQLite call fails.
788    #[inline]
789    pub fn prepare(&self, sql: &str) -> Result<Statement<'_>> {
790        self.prepare_with_flags(sql, PrepFlags::default())
791    }
792
793    /// Prepare a SQL statement for execution.
794    ///
795    /// # Failure
796    ///
797    /// Will return `Err` if `sql` cannot be converted to a C-compatible string
798    /// or if the underlying SQLite call fails.
799    #[inline]
800    pub fn prepare_with_flags(&self, sql: &str, flags: PrepFlags) -> Result<Statement<'_>> {
801        let (stmt, tail) = self.db.borrow_mut().prepare(self, sql, flags)?;
802        if tail != 0 && !self.prepare(&sql[tail..])?.stmt.is_null() {
803            Err(Error::MultipleStatement)
804        } else {
805            Ok(stmt)
806        }
807    }
808
809    /// Close the SQLite connection.
810    ///
811    /// This is functionally equivalent to the `Drop` implementation for
812    /// `Connection` except that on failure, it returns an error and the
813    /// connection itself (presumably so closing can be attempted again).
814    ///
815    /// # Failure
816    ///
817    /// Will return `Err` if the underlying SQLite call fails.
818    #[expect(clippy::result_large_err)]
819    #[inline]
820    pub fn close(self) -> Result<(), (Self, Error)> {
821        #[cfg(feature = "cache")]
822        self.flush_prepared_statement_cache();
823        let r = self.db.borrow_mut().close();
824        r.map_err(move |err| (self, err))
825    }
826
827    /// Enable loading of SQLite extensions from both SQL queries and Rust.
828    ///
829    /// You must call [`Connection::load_extension_disable`] when you're
830    /// finished loading extensions (failure to call it can lead to bad things,
831    /// see "Safety"), so you should strongly consider using
832    /// [`LoadExtensionGuard`] instead of this function, automatically disables
833    /// extension loading when it goes out of scope.
834    ///
835    /// # Example
836    ///
837    /// ```rust,no_run
838    /// # use rusqlite::{Connection, DEFAULT_NAME, Result};
839    /// fn load_my_extension(conn: &Connection) -> Result<()> {
840    ///     // Safety: We fully trust the loaded extension and execute no untrusted SQL
841    ///     // while extension loading is enabled.
842    ///     unsafe {
843    ///         conn.load_extension_enable()?;
844    ///         let r = conn.load_extension("my/trusted/extension", DEFAULT_NAME);
845    ///         conn.load_extension_disable()?;
846    ///         r
847    ///     }
848    /// }
849    /// ```
850    ///
851    /// # Failure
852    ///
853    /// Will return `Err` if the underlying SQLite call fails.
854    ///
855    /// # Safety
856    ///
857    /// TLDR: Don't execute any untrusted queries between this call and
858    /// [`Connection::load_extension_disable`].
859    ///
860    /// Perhaps surprisingly, this function does not only allow the use of
861    /// [`Connection::load_extension`] from Rust, but it also allows SQL queries
862    /// to perform [the same operation][loadext]. For example, in the period
863    /// between `load_extension_enable` and `load_extension_disable`, the
864    /// following operation will load and call some function in some dynamic
865    /// library:
866    ///
867    /// ```sql
868    /// SELECT load_extension('why_is_this_possible.dll', 'dubious_func');
869    /// ```
870    ///
871    /// This means that while this is enabled a carefully crafted SQL query can
872    /// be used to escalate a SQL injection attack into code execution.
873    ///
874    /// Safely using this function requires that you trust all SQL queries run
875    /// between when it is called, and when loading is disabled (by
876    /// [`Connection::load_extension_disable`]).
877    ///
878    /// [loadext]: https://www.sqlite.org/lang_corefunc.html#load_extension
879    #[cfg(feature = "load_extension")]
880    #[inline]
881    pub unsafe fn load_extension_enable(&self) -> Result<()> {
882        unsafe { self.db.borrow_mut().enable_load_extension(1) }
883    }
884
885    /// Disable loading of SQLite extensions.
886    ///
887    /// See [`Connection::load_extension_enable`] for an example.
888    ///
889    /// # Failure
890    ///
891    /// Will return `Err` if the underlying SQLite call fails.
892    #[cfg(feature = "load_extension")]
893    #[inline]
894    pub fn load_extension_disable(&self) -> Result<()> {
895        // It's always safe to turn off extension loading.
896        unsafe { self.db.borrow_mut().enable_load_extension(0) }
897    }
898
899    /// Load the SQLite extension at `dylib_path`. `dylib_path` is passed
900    /// through to `sqlite3_load_extension`, which may attempt OS-specific
901    /// modifications if the file cannot be loaded directly (for example
902    /// converting `"some/ext"` to `"some/ext.so"`, `"some\\ext.dll"`, ...).
903    ///
904    /// If `entry_point` is `None`, SQLite will attempt to find the entry point.
905    /// If it is not `None`, the entry point will be passed through to
906    /// `sqlite3_load_extension`.
907    ///
908    /// ## Example
909    ///
910    /// ```rust,no_run
911    /// # use rusqlite::{Connection, DEFAULT_NAME, Result, LoadExtensionGuard};
912    /// fn load_my_extension(conn: &Connection) -> Result<()> {
913    ///     // Safety: we don't execute any SQL statements while
914    ///     // extension loading is enabled.
915    ///     let _guard = unsafe { LoadExtensionGuard::new(conn)? };
916    ///     // Safety: `my_sqlite_extension` is highly trustworthy.
917    ///     unsafe { conn.load_extension("my_sqlite_extension", DEFAULT_NAME) }
918    /// }
919    /// ```
920    ///
921    /// # Failure
922    ///
923    /// Will return `Err` if the underlying SQLite call fails.
924    ///
925    /// # Safety
926    ///
927    /// This is equivalent to performing a `dlopen`/`LoadLibrary` on a shared
928    /// library, and calling a function inside, and thus requires that you trust
929    /// the library that you're loading.
930    ///
931    /// That is to say: to safely use this, the code in the extension must be
932    /// sound, trusted, correctly use the SQLite APIs, and not contain any
933    /// memory or thread safety errors.
934    #[cfg(feature = "load_extension")]
935    #[inline]
936    pub unsafe fn load_extension<P: AsRef<Path>, N: Name>(
937        &self,
938        dylib_path: P,
939        entry_point: Option<N>,
940    ) -> Result<()> {
941        unsafe {
942            self.db
943                .borrow_mut()
944                .load_extension(dylib_path.as_ref(), entry_point)
945        }
946    }
947
948    /// Get access to the underlying SQLite database connection handle.
949    ///
950    /// # Warning
951    ///
952    /// You should not need to use this function. If you do need to, please
953    /// [open an issue on the rusqlite repository](https://github.com/rusqlite/rusqlite/issues) and describe
954    /// your use case.
955    ///
956    /// # Safety
957    ///
958    /// This function is unsafe because it gives you raw access
959    /// to the SQLite connection, and what you do with it could impact the
960    /// safety of this `Connection`.
961    #[inline]
962    pub unsafe fn handle(&self) -> *mut ffi::sqlite3 {
963        self.db.borrow().db()
964    }
965
966    /// Create a `Connection` from a raw handle.
967    ///
968    /// The underlying SQLite database connection handle will not be closed when
969    /// the returned connection is dropped/closed.
970    ///
971    /// # Safety
972    ///
973    /// This function is unsafe because improper use may impact the Connection.
974    #[inline]
975    pub unsafe fn from_handle(db: *mut ffi::sqlite3) -> Result<Self> {
976        let db = unsafe { InnerConnection::new(db, false) };
977        Ok(Self {
978            db: RefCell::new(db),
979            #[cfg(feature = "cache")]
980            cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
981            transaction_behavior: TransactionBehavior::Deferred,
982        })
983    }
984
985    /// Helper to register an SQLite extension written in Rust.
986    /// For [persistent](https://sqlite.org/loadext.html#persistent_loadable_extensions) extension,
987    /// `init` should return `Ok(true)`.
988    /// # Safety
989    /// * Results are undefined if `init` does not just register features.
990    #[cfg(feature = "loadable_extension")]
991    pub unsafe fn extension_init2(
992        db: *mut ffi::sqlite3,
993        pz_err_msg: *mut *mut c_char,
994        p_api: *mut ffi::sqlite3_api_routines,
995        init: fn(Self) -> Result<bool>,
996    ) -> c_int {
997        if p_api.is_null() {
998            return ffi::SQLITE_ERROR;
999        }
1000        unsafe {
1001            match ffi::rusqlite_extension_init2(p_api)
1002                .map_err(Error::from)
1003                .and(Self::from_handle(db))
1004                .and_then(init)
1005            {
1006                Err(err) => to_sqlite_error(&err, pz_err_msg),
1007                Ok(true) => ffi::SQLITE_OK_LOAD_PERMANENTLY,
1008                _ => ffi::SQLITE_OK,
1009            }
1010        }
1011    }
1012
1013    /// Create a `Connection` from a raw owned handle.
1014    ///
1015    /// The returned connection will attempt to close the inner connection
1016    /// when dropped/closed. This function should only be called on connections
1017    /// owned by the caller.
1018    ///
1019    /// # Safety
1020    ///
1021    /// This function is unsafe because improper use may impact the Connection.
1022    /// In particular, it should only be called on connections created
1023    /// and owned by the caller, e.g. as a result of calling
1024    /// `ffi::sqlite3_open`().
1025    #[inline]
1026    pub unsafe fn from_handle_owned(db: *mut ffi::sqlite3) -> Result<Self> {
1027        let db = unsafe { InnerConnection::new(db, true) };
1028        Ok(Self {
1029            db: RefCell::new(db),
1030            #[cfg(feature = "cache")]
1031            cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
1032            transaction_behavior: TransactionBehavior::Deferred,
1033        })
1034    }
1035
1036    /// Get access to a handle that can be used to interrupt long-running
1037    /// queries from another thread.
1038    #[inline]
1039    pub fn get_interrupt_handle(&self) -> InterruptHandle {
1040        self.db.borrow().get_interrupt_handle()
1041    }
1042
1043    #[inline]
1044    fn decode_result(&self, code: c_int) -> Result<()> {
1045        self.db.borrow().decode_result(code)
1046    }
1047
1048    /// Return the number of rows modified, inserted or deleted by the most
1049    /// recently completed INSERT, UPDATE or DELETE statement on the database
1050    /// connection.
1051    ///
1052    /// See <https://www.sqlite.org/c3ref/changes.html>
1053    #[inline]
1054    pub fn changes(&self) -> u64 {
1055        self.db.borrow().changes()
1056    }
1057
1058    /// Return the total number of rows modified, inserted or deleted by all
1059    /// completed INSERT, UPDATE or DELETE statements since the database
1060    /// connection was opened, including those executed as part of trigger programs.
1061    ///
1062    /// See <https://www.sqlite.org/c3ref/total_changes.html>
1063    #[inline]
1064    pub fn total_changes(&self) -> u64 {
1065        self.db.borrow().total_changes()
1066    }
1067
1068    /// Test for auto-commit mode.
1069    /// Autocommit mode is on by default.
1070    #[inline]
1071    pub fn is_autocommit(&self) -> bool {
1072        self.db.borrow().is_autocommit()
1073    }
1074
1075    /// Determine if all associated prepared statements have been reset.
1076    #[inline]
1077    pub fn is_busy(&self) -> bool {
1078        self.db.borrow().is_busy()
1079    }
1080
1081    /// Flush caches to disk mid-transaction
1082    pub fn cache_flush(&self) -> Result<()> {
1083        self.db.borrow_mut().cache_flush()
1084    }
1085
1086    /// Determine if a database is read-only
1087    pub fn is_readonly<N: Name>(&self, db_name: N) -> Result<bool> {
1088        self.db.borrow().db_readonly(db_name)
1089    }
1090
1091    /// Return the schema name for a database connection
1092    ///
1093    /// ## Failure
1094    ///
1095    /// Return an `Error::InvalidDatabaseIndex` if `index` is out of range.
1096    pub fn db_name(&self, index: usize) -> Result<String> {
1097        unsafe {
1098            let db = self.handle();
1099            let name = ffi::sqlite3_db_name(db, index as c_int);
1100            if name.is_null() {
1101                Err(Error::InvalidDatabaseIndex(index))
1102            } else {
1103                Ok(CStr::from_ptr(name).to_str()?.to_owned())
1104            }
1105        }
1106    }
1107
1108    /// Determine whether an interrupt is currently in effect
1109    pub fn is_interrupted(&self) -> bool {
1110        self.db.borrow().is_interrupted()
1111    }
1112
1113    /// Set client Data
1114    ///
1115    /// # Safety
1116    /// This function is unsafe because it returns a raw pointer.
1117    /// You should not alter the callbacks stored by `rusqlite`.
1118    pub unsafe fn set_clientdata<T: Send + 'static, N: Name>(
1119        &self,
1120        name: N,
1121        data: Option<T>,
1122    ) -> Result<*mut T> {
1123        self.db
1124            .borrow_mut()
1125            .set_clientdata(name, data, |_, _| ffi::SQLITE_OK)
1126    }
1127    /// Retrieve client data
1128    ///
1129    /// # Safety
1130    /// Caller must be certain that data associated to `name` is of type `T`.
1131    pub unsafe fn get_clientdata<T, N: Name>(&self, name: N) -> Result<Option<&T>> {
1132        unsafe {
1133            self.db
1134                .borrow()
1135                .get_clientdata(name)
1136                .map(|p: *mut T| p.as_ref())
1137        }
1138    }
1139
1140    /// Set error code and message
1141    #[cfg(feature = "modern_sqlite")] // 3.51.0
1142    pub fn set_errmsg(&self, code: c_int, msg: Option<&CStr>) -> Result<()> {
1143        unsafe { error::set_errmsg(self.handle(), code, msg) }
1144    }
1145
1146    /// Low-level control of database files
1147    ///
1148    /// See `https://sqlite.org/c3ref/file_control.html` for details.
1149    pub fn file_control<N: Name>(&self, db_name: Option<N>, op_and_arg: FileControl) -> Result<()> {
1150        fn to_void<X>(r: &mut X) -> *mut c_void {
1151            std::ptr::from_mut(r).cast::<c_void>()
1152        }
1153        let (op, arg) = match op_and_arg {
1154            FileControl::SizeHint(p) => (ffi::SQLITE_FCNTL_SIZE_HINT, to_void(p)),
1155            FileControl::SizeLimit(p) => (ffi::SQLITE_FCNTL_SIZE_LIMIT, to_void(p)),
1156            FileControl::ChunkSize(p) => (ffi::SQLITE_FCNTL_CHUNK_SIZE, to_void(p)),
1157            FileControl::PersistWal(p) => (ffi::SQLITE_FCNTL_PERSIST_WAL, to_void(p)),
1158            FileControl::PowerSafeOverwrite(p) => {
1159                (ffi::SQLITE_FCNTL_POWERSAFE_OVERWRITE, to_void(p))
1160            }
1161            FileControl::MMapSize(p) => (ffi::SQLITE_FCNTL_MMAP_SIZE, to_void(p)),
1162            #[cfg(unix)]
1163            FileControl::HasMoved(p) => (ffi::SQLITE_FCNTL_HAS_MOVED, to_void(p)),
1164            FileControl::LockTimeout(p) => (ffi::SQLITE_FCNTL_LOCK_TIMEOUT, to_void(p)),
1165            #[cfg(feature = "modern_sqlite")]
1166            FileControl::BlockOnConnect(p) => (ffi::SQLITE_FCNTL_BLOCK_ON_CONNECT, to_void(p)),
1167            FileControl::DataVersion(p) => (ffi::SQLITE_FCNTL_DATA_VERSION, to_void(p)),
1168            FileControl::ReserveBytes(p) => (ffi::SQLITE_FCNTL_RESERVE_BYTES, to_void(p)),
1169        };
1170        unsafe { self.db.borrow().file_control(db_name, op, arg) }
1171    }
1172}
1173
1174impl fmt::Debug for Connection {
1175    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1176        f.debug_struct("Connection")
1177            .field("path", &self.path())
1178            .finish()
1179    }
1180}
1181
1182/// Batch fallible iterator
1183///
1184/// # Warning
1185///
1186/// There is no recovery on parsing error, when an invalid statement is found in `sql`, SQLite cannot jump to the next statement.
1187/// So you should break the loop when an error is raised by the `next` method.
1188///
1189/// ```rust
1190/// use fallible_iterator::FallibleIterator;
1191/// use rusqlite::{Batch, Connection, Result};
1192///
1193/// fn main() -> Result<()> {
1194///     let conn = Connection::open_in_memory()?;
1195///     let sql = r"
1196///     CREATE TABLE tbl1 (col);
1197///     CREATE TABLE tbl2 (col);
1198///     ";
1199///     let mut batch = Batch::new(&conn, sql);
1200///     while let Some(mut stmt) = batch.next()? {
1201///         stmt.execute([])?;
1202///     }
1203///     Ok(())
1204/// }
1205/// ```
1206#[derive(Debug)]
1207pub struct Batch<'conn, 'sql> {
1208    conn: &'conn Connection,
1209    sql: &'sql str,
1210    tail: usize,
1211}
1212
1213impl<'conn, 'sql> Batch<'conn, 'sql> {
1214    /// Constructor
1215    pub fn new(conn: &'conn Connection, sql: &'sql str) -> Self {
1216        Batch { conn, sql, tail: 0 }
1217    }
1218}
1219impl<'conn> fallible_iterator::FallibleIterator for Batch<'conn, '_> {
1220    type Error = Error;
1221    type Item = Statement<'conn>;
1222
1223    /// Iterates on each batch statements.
1224    ///
1225    /// Returns `Ok(None)` when batch is completed.
1226    fn next(&mut self) -> Result<Option<Statement<'conn>>> {
1227        while self.tail < self.sql.len() {
1228            let sql = &self.sql[self.tail..];
1229            let (next, tail) =
1230                self.conn
1231                    .db
1232                    .borrow_mut()
1233                    .prepare(self.conn, sql, PrepFlags::default())?;
1234            if tail == 0 {
1235                self.tail = self.sql.len();
1236            } else {
1237                self.tail += tail;
1238            }
1239            if next.stmt.is_null() {
1240                continue;
1241            }
1242            return Ok(Some(next));
1243        }
1244        Ok(None)
1245    }
1246}
1247
1248bitflags::bitflags! {
1249    /// Flags for opening SQLite database connections. See
1250    /// [sqlite3_open_v2](https://www.sqlite.org/c3ref/open.html) for details.
1251    ///
1252    /// The default open flags are `SQLITE_OPEN_READ_WRITE | SQLITE_OPEN_CREATE
1253    /// | SQLITE_OPEN_URI | SQLITE_OPEN_NO_MUTEX`. See [`Connection::open`] for
1254    /// some discussion about these flags.
1255    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1256    #[repr(C)]
1257    pub struct OpenFlags: c_int {
1258        /// The database is opened in read-only mode.
1259        /// If the database does not already exist, an error is returned.
1260        const SQLITE_OPEN_READ_ONLY = ffi::SQLITE_OPEN_READONLY;
1261        /// The database is opened for reading and writing if possible,
1262        /// or reading only if the file is write-protected by the operating system.
1263        /// In either case the database must already exist, otherwise an error is returned.
1264        const SQLITE_OPEN_READ_WRITE = ffi::SQLITE_OPEN_READWRITE;
1265        /// The database is created if it does not already exist
1266        const SQLITE_OPEN_CREATE = ffi::SQLITE_OPEN_CREATE;
1267        /// The filename can be interpreted as a URI if this flag is set.
1268        const SQLITE_OPEN_URI = ffi::SQLITE_OPEN_URI;
1269        /// The database will be opened as an in-memory database.
1270        const SQLITE_OPEN_MEMORY = ffi::SQLITE_OPEN_MEMORY;
1271        /// The new database connection will not use a per-connection mutex (the
1272        /// connection will use the "multi-thread" threading mode, in SQLite
1273        /// parlance).
1274        ///
1275        /// This is used by default, as proper `Send`/`Sync` usage (in
1276        /// particular, the fact that [`Connection`] does not implement `Sync`)
1277        /// ensures thread-safety without the need to perform locking around all
1278        /// calls.
1279        const SQLITE_OPEN_NO_MUTEX = ffi::SQLITE_OPEN_NOMUTEX;
1280        /// The new database connection will use a per-connection mutex -- the
1281        /// "serialized" threading mode, in SQLite parlance.
1282        ///
1283        /// # Caveats
1284        ///
1285        /// This flag should probably never be used with `rusqlite`, as we
1286        /// ensure thread-safety statically (we implement [`Send`] and not
1287        /// [`Sync`]).
1288        ///
1289        /// Critically, even if this flag is used, the [`Connection`] is not
1290        /// safe to use across multiple threads simultaneously. To access a
1291        /// database from multiple threads, you should either create multiple
1292        /// connections, one for each thread (if you have very many threads,
1293        /// wrapping the `rusqlite::Connection` in a mutex is also reasonable).
1294        ///
1295        /// This is both because of the additional per-connection state stored
1296        /// by `rusqlite` (for example, the prepared statement cache), and
1297        /// because not all of SQLites functions are fully thread safe, even in
1298        /// serialized/`SQLITE_OPEN_FULLMUTEX` mode.
1299        ///
1300        /// All that said, it's fairly harmless to enable this flag with
1301        /// `rusqlite`, it will just slow things down while providing no
1302        /// benefit.
1303        const SQLITE_OPEN_FULL_MUTEX = ffi::SQLITE_OPEN_FULLMUTEX;
1304        /// The database is opened with shared cache enabled.
1305        ///
1306        /// This is frequently useful for in-memory connections, but note that
1307        /// broadly speaking it's discouraged by SQLite itself, which states
1308        /// "Any use of shared cache is discouraged" in the official
1309        /// [documentation](https://www.sqlite.org/c3ref/enable_shared_cache.html).
1310        const SQLITE_OPEN_SHARED_CACHE = 0x0002_0000;
1311        /// The database is opened shared cache disabled.
1312        const SQLITE_OPEN_PRIVATE_CACHE = 0x0004_0000;
1313        /// The database filename is not allowed to be a symbolic link. (3.31.0)
1314        const SQLITE_OPEN_NOFOLLOW = 0x0100_0000;
1315        /// Extended result codes. (3.37.0)
1316        const SQLITE_OPEN_EXRESCODE = 0x0200_0000;
1317    }
1318}
1319
1320impl Default for OpenFlags {
1321    #[inline]
1322    fn default() -> Self {
1323        // Note: update the `Connection::open` and top-level `OpenFlags` docs if
1324        // you change these.
1325        Self::SQLITE_OPEN_READ_WRITE
1326            | Self::SQLITE_OPEN_CREATE
1327            | Self::SQLITE_OPEN_NO_MUTEX
1328            | Self::SQLITE_OPEN_URI
1329    }
1330}
1331
1332bitflags::bitflags! {
1333    /// Prepare flags. See
1334    /// [sqlite3_prepare_v3](https://sqlite.org/c3ref/c_prepare_dont_log.html) for details.
1335    #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
1336    #[repr(C)]
1337    pub struct PrepFlags: c_uint {
1338        /// A hint to the query planner that the prepared statement will be retained for a long time and probably reused many times.
1339        const SQLITE_PREPARE_PERSISTENT = 0x01;
1340        /// Causes the SQL compiler to return an error (error code SQLITE_ERROR) if the statement uses any virtual tables.
1341        const SQLITE_PREPARE_NO_VTAB = 0x04;
1342        /// Prevents SQL compiler errors from being sent to the error log.
1343        const SQLITE_PREPARE_DONT_LOG = 0x10;
1344        /// Causes the SQL compiler to enforce security constraints that would otherwise only be enforced when parsing
1345        /// the database schema.
1346        const SQLITE_PREPARE_FROM_DDL = 0x20; // 3.53.0
1347    }
1348}
1349
1350/// Allows interrupting a long-running computation.
1351pub struct InterruptHandle {
1352    db_lock: Arc<Mutex<*mut ffi::sqlite3>>,
1353}
1354
1355unsafe impl Send for InterruptHandle {}
1356unsafe impl Sync for InterruptHandle {}
1357
1358impl InterruptHandle {
1359    /// Interrupt the query currently executing on another thread. This will
1360    /// cause that query to fail with a `SQLITE3_INTERRUPT` error.
1361    pub fn interrupt(&self) {
1362        let db_handle = self.db_lock.lock().unwrap();
1363        if !db_handle.is_null() {
1364            unsafe { ffi::sqlite3_interrupt(*db_handle) }
1365        }
1366    }
1367}
1368
1369/// Standard File Control Opcodes
1370///
1371/// See `https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html` for explanations of each.
1372#[derive(Debug)]
1373#[non_exhaustive]
1374pub enum FileControl<'p> {
1375    // Write the current state of the lock
1376    //LockState = ffi::SQLITE_FCNTL_LOCKSTATE,
1377    /// Give the VFS layer a hint of how large the database file will grow to be during the current transaction.
1378    SizeHint(&'p mut ffi::sqlite3_int64),
1379    /// Used by in-memory VFS that implements `sqlite3_deserialize()` to set an upper bound on the size of the in-memory database.
1380    SizeLimit(&'p mut ffi::sqlite3_int64),
1381    /// Used to request that the VFS extends and truncates the database file in chunks of a size specified by the user.
1382    ChunkSize(&'p mut c_int),
1383    /// Used to set or query the persistent Write Ahead Log setting.
1384    PersistWal(&'p mut c_int),
1385    /// Used to set or query the persistent "powersafe-overwrite" or "PSOW" setting.
1386    PowerSafeOverwrite(&'p mut c_int),
1387    /// Used to query or set the maximum number of bytes that will be used for memory-mapped I/O.
1388    MMapSize(&'p mut ffi::sqlite3_int64),
1389    /// Whether or not the file has been renamed, moved, or deleted since it was first opened.
1390    #[cfg(unix)]
1391    HasMoved(&'p mut c_int),
1392    /// Used to configure a VFS to block for up to M milliseconds before failing when attempting to obtain a file lock using the xLock or xShmLock methods of the VFS.
1393    LockTimeout(&'p mut c_int),
1394    /// Used to configure the VFS to block when taking a SHARED lock to connect to a wal mode database.
1395    #[cfg(feature = "modern_sqlite")]
1396    BlockOnConnect(&'p mut c_int),
1397    /// Detect changes to a database file.
1398    DataVersion(&'p mut c_uint),
1399    /// Used to query or set the reserve bytes
1400    ReserveBytes(&'p mut c_int),
1401}
1402
1403#[cfg(doctest)]
1404doc_comment::doctest!("../README.md");
1405
1406#[cfg(all(test, not(miri)))]
1407mod test {
1408    use std::assert_matches;
1409    #[cfg(all(target_family = "wasm", target_os = "unknown"))]
1410    use wasm_bindgen_test::wasm_bindgen_test as test;
1411
1412    use super::*;
1413    use fallible_iterator::FallibleIterator as _;
1414    use std::error::Error as StdError;
1415    use std::fmt;
1416
1417    // this function is never called, but is still type checked; in
1418    // particular, calls with specific instantiations will require
1419    // that those types are `Send`.
1420    #[allow(dead_code)]
1421    #[expect(unconditional_recursion, clippy::extra_unused_type_parameters)]
1422    fn ensure_send<T: Send>() {
1423        ensure_send::<Connection>();
1424        ensure_send::<InterruptHandle>();
1425    }
1426
1427    #[allow(dead_code)]
1428    #[expect(unconditional_recursion, clippy::extra_unused_type_parameters)]
1429    fn ensure_sync<T: Sync>() {
1430        ensure_sync::<InterruptHandle>();
1431    }
1432
1433    fn checked_memory_handle() -> Connection {
1434        Connection::open_in_memory().unwrap()
1435    }
1436
1437    #[cfg_attr(
1438        all(target_family = "wasm", target_os = "unknown"),
1439        ignore = "no filesystem on this platform"
1440    )]
1441    #[test]
1442    fn test_concurrent_transactions_busy_commit() -> Result<()> {
1443        use std::time::Duration;
1444        let tmp = tempfile::tempdir().unwrap();
1445        let path = tmp.path().join("transactions.db3");
1446
1447        Connection::open(&path)?.execute_batch(
1448            "
1449            BEGIN; CREATE TABLE foo(x INTEGER);
1450            INSERT INTO foo VALUES(42); END;",
1451        )?;
1452
1453        let mut db1 = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_WRITE)?;
1454        let mut db2 = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_ONLY)?;
1455
1456        db1.busy_timeout(Duration::from_millis(0))?;
1457        db2.busy_timeout(Duration::from_millis(0))?;
1458
1459        {
1460            let tx1 = db1.transaction()?;
1461            let tx2 = db2.transaction()?;
1462
1463            // SELECT first makes sqlite lock with a shared lock
1464            tx1.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))?;
1465            tx2.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))?;
1466
1467            tx1.execute("INSERT INTO foo VALUES(?1)", [1])?;
1468            let _ = tx2.execute("INSERT INTO foo VALUES(?1)", [2]);
1469
1470            let _ = tx1.commit();
1471            let _ = tx2.commit();
1472        }
1473
1474        let _ = db1
1475            .transaction()
1476            .expect("commit should have closed transaction");
1477        let _ = db2
1478            .transaction()
1479            .expect("commit should have closed transaction");
1480        Ok(())
1481    }
1482
1483    #[cfg_attr(
1484        all(target_family = "wasm", target_os = "unknown"),
1485        ignore = "no filesystem on this platform"
1486    )]
1487    #[test]
1488    fn test_persistence() -> Result<()> {
1489        let temp_dir = tempfile::tempdir().unwrap();
1490        let path = temp_dir.path().join("test.db3");
1491
1492        {
1493            let db = Connection::open(&path)?;
1494            let sql = "BEGIN;
1495                   CREATE TABLE foo(x INTEGER);
1496                   INSERT INTO foo VALUES(42);
1497                   END;";
1498            db.execute_batch(sql)?;
1499        }
1500
1501        let path_string = path.to_str().unwrap();
1502        let db = Connection::open(path_string)?;
1503
1504        assert_eq!(42, db.one_column::<i64, _>("SELECT x FROM foo", [])?);
1505        Ok(())
1506    }
1507
1508    #[test]
1509    fn test_open() {
1510        Connection::open_in_memory().unwrap();
1511
1512        let db = checked_memory_handle();
1513        db.close().unwrap();
1514    }
1515
1516    #[cfg_attr(
1517        all(target_family = "wasm", target_os = "unknown"),
1518        ignore = "no filesystem on this platform"
1519    )]
1520    #[test]
1521    fn test_path() -> Result<()> {
1522        let tmp = tempfile::tempdir().unwrap();
1523        let db = Connection::open("")?;
1524        assert_eq!(Some(""), db.path());
1525        let db = Connection::open_in_memory()?;
1526        assert_eq!(Some(""), db.path());
1527        let db = Connection::open("file:dummy.db?mode=memory&cache=shared")?;
1528        assert_eq!(Some(""), db.path());
1529        let path = tmp.path().join("file.db");
1530        let db = Connection::open(path)?;
1531        assert!(db.path().is_some_and(|p| p.ends_with("file.db")));
1532        Ok(())
1533    }
1534
1535    #[test]
1536    fn test_open_failure() {
1537        let filename = "no_such_file.db";
1538        assert_matches!(
1539            Connection::open_with_flags(filename, OpenFlags::SQLITE_OPEN_READ_ONLY),
1540            Err(Error::SqliteFailure(
1541                ffi::Error {
1542                    code: ErrorCode::CannotOpen,
1543                    extended_code: ffi::SQLITE_CANTOPEN,
1544                },
1545                Some(msg)
1546            )) if msg.contains(filename)
1547        );
1548    }
1549
1550    #[cfg(unix)]
1551    #[test]
1552    fn test_invalid_unicode_file_names() -> Result<()> {
1553        use std::ffi::OsStr;
1554        use std::fs::File;
1555        use std::os::unix::ffi::OsStrExt as _;
1556        let temp_dir = tempfile::tempdir().unwrap();
1557
1558        let path = temp_dir.path();
1559        if File::create(path.join(OsStr::from_bytes(&[0xFE]))).is_err() {
1560            // Skip test, filesystem doesn't support invalid Unicode
1561            return Ok(());
1562        }
1563        let db_path = path.join(OsStr::from_bytes(&[0xFF]));
1564        {
1565            let db = Connection::open(&db_path)?;
1566            let sql = "BEGIN;
1567                   CREATE TABLE foo(x INTEGER);
1568                   INSERT INTO foo VALUES(42);
1569                   END;";
1570            db.execute_batch(sql)?;
1571        }
1572
1573        let db = Connection::open(&db_path)?;
1574
1575        assert_eq!(42, db.one_column::<i64, _>("SELECT x FROM foo", [])?);
1576        Ok(())
1577    }
1578
1579    #[test]
1580    fn test_close_retry() -> Result<()> {
1581        let db = Connection::open_in_memory()?;
1582
1583        // force the DB to be busy by preparing a statement; this must be done at the
1584        // FFI level to allow us to call .close() without dropping the prepared
1585        // statement first.
1586        let raw_stmt = {
1587            use super::str_to_cstring;
1588            use std::ffi::c_int;
1589            use std::ptr;
1590
1591            let raw_db = db.db.borrow_mut().db;
1592            let sql = "SELECT 1";
1593            let mut raw_stmt: *mut ffi::sqlite3_stmt = ptr::null_mut();
1594            let cstring = str_to_cstring(sql)?;
1595            let rc = unsafe {
1596                ffi::sqlite3_prepare_v2(
1597                    raw_db,
1598                    cstring.as_ptr(),
1599                    (sql.len() + 1) as c_int,
1600                    &mut raw_stmt,
1601                    ptr::null_mut(),
1602                )
1603            };
1604            assert_eq!(rc, ffi::SQLITE_OK);
1605            raw_stmt
1606        };
1607
1608        // now that we have an open statement, trying (and retrying) to close should
1609        // fail.
1610        let (db, _) = db.close().unwrap_err();
1611        let (db, _) = db.close().unwrap_err();
1612        let (db, _) = db.close().unwrap_err();
1613
1614        // finalize the open statement so a final close will succeed
1615        assert_eq!(ffi::SQLITE_OK, unsafe { ffi::sqlite3_finalize(raw_stmt) });
1616
1617        db.close().unwrap();
1618        Ok(())
1619    }
1620
1621    #[test]
1622    fn test_open_with_flags() {
1623        for bad_flags in &[
1624            OpenFlags::empty(),
1625            OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_READ_WRITE,
1626            OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_CREATE,
1627        ] {
1628            Connection::open_in_memory_with_flags(*bad_flags).unwrap_err();
1629        }
1630    }
1631
1632    #[test]
1633    fn test_execute_batch() -> Result<()> {
1634        let db = Connection::open_in_memory()?;
1635        let sql = "BEGIN;
1636                   CREATE TABLE foo(x INTEGER);
1637                   INSERT INTO foo VALUES(1);
1638                   INSERT INTO foo VALUES(2);
1639                   INSERT INTO foo VALUES(3);
1640                   INSERT INTO foo VALUES(4);
1641                   END;";
1642        db.execute_batch(sql)?;
1643
1644        db.execute_batch("UPDATE foo SET x = 3 WHERE x < 3")?;
1645
1646        db.execute_batch("INVALID SQL").unwrap_err();
1647
1648        db.execute_batch("PRAGMA locking_mode = EXCLUSIVE")?;
1649        Ok(())
1650    }
1651
1652    #[test]
1653    fn test_execute() -> Result<()> {
1654        let db = Connection::open_in_memory()?;
1655        db.execute_batch("CREATE TABLE foo(x INTEGER)")?;
1656
1657        assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?1)", [1i32])?);
1658        assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?1)", [2i32])?);
1659
1660        assert_eq!(3, db.one_column::<i32, _>("SELECT SUM(x) FROM foo", [])?);
1661        Ok(())
1662    }
1663
1664    #[test]
1665    #[cfg(feature = "extra_check")]
1666    fn test_execute_select_with_no_row() {
1667        let db = checked_memory_handle();
1668        let err = db.execute("SELECT 1 WHERE 1 < ?1", [1i32]).unwrap_err();
1669        assert_eq!(
1670            err,
1671            Error::ExecuteReturnedResults,
1672            "Unexpected error: {err}"
1673        );
1674    }
1675
1676    #[test]
1677    fn test_execute_select_with_row() {
1678        let db = checked_memory_handle();
1679        let err = db.execute("SELECT 1", []).unwrap_err();
1680        assert_eq!(err, Error::ExecuteReturnedResults);
1681    }
1682
1683    #[test]
1684    fn test_execute_multiple() {
1685        let db = checked_memory_handle();
1686        let err = db
1687            .execute(
1688                "CREATE TABLE foo(x INTEGER); CREATE TABLE foo(x INTEGER)",
1689                [],
1690            )
1691            .unwrap_err();
1692        match err {
1693            Error::MultipleStatement => (),
1694            _ => panic!("Unexpected error: {err}"),
1695        }
1696        db.execute("CREATE TABLE t(c); -- bim", [])
1697            .expect("Tail comment should be ignored");
1698    }
1699
1700    #[test]
1701    fn test_prepare_column_names() -> Result<()> {
1702        let db = Connection::open_in_memory()?;
1703        db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1704
1705        let stmt = db.prepare("SELECT * FROM foo")?;
1706        assert_eq!(stmt.column_count(), 1);
1707        assert_eq!(stmt.column_names().collect::<Vec<_>>(), vec!["x"]);
1708
1709        let stmt = db.prepare("SELECT x AS a, x AS b FROM foo")?;
1710        assert_eq!(stmt.column_count(), 2);
1711        assert_eq!(stmt.column_names().collect::<Vec<_>>(), vec!["a", "b"]);
1712        Ok(())
1713    }
1714
1715    #[test]
1716    fn test_prepare_execute() -> Result<()> {
1717        let db = Connection::open_in_memory()?;
1718        db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1719
1720        let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?1)")?;
1721        assert_eq!(insert_stmt.execute([1i32])?, 1);
1722        assert_eq!(insert_stmt.execute([2i32])?, 1);
1723        assert_eq!(insert_stmt.execute([3i32])?, 1);
1724
1725        assert_eq!(insert_stmt.execute(["hello"])?, 1);
1726        assert_eq!(insert_stmt.execute(["goodbye"])?, 1);
1727        assert_eq!(insert_stmt.execute([types::Null])?, 1);
1728
1729        let mut update_stmt = db.prepare("UPDATE foo SET x=?1 WHERE x<?2")?;
1730        assert_eq!(update_stmt.execute([3i32, 3i32])?, 2);
1731        assert_eq!(update_stmt.execute([3i32, 3i32])?, 0);
1732        assert_eq!(update_stmt.execute([8i32, 8i32])?, 3);
1733        Ok(())
1734    }
1735
1736    #[test]
1737    fn test_prepare_query() -> Result<()> {
1738        let db = Connection::open_in_memory()?;
1739        db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1740
1741        let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?1)")?;
1742        assert_eq!(insert_stmt.execute([1i32])?, 1);
1743        assert_eq!(insert_stmt.execute([2i32])?, 1);
1744        assert_eq!(insert_stmt.execute([3i32])?, 1);
1745
1746        let mut query = db.prepare("SELECT x FROM foo WHERE x < ?1 ORDER BY x DESC")?;
1747        {
1748            let mut rows = query.query([4i32])?;
1749            let mut v = Vec::<i32>::new();
1750
1751            while let Some(row) = rows.next()? {
1752                v.push(row.get(0)?);
1753            }
1754
1755            assert_eq!(v, [3i32, 2, 1]);
1756        }
1757
1758        {
1759            let mut rows = query.query([3i32])?;
1760            let mut v = Vec::<i32>::new();
1761
1762            while let Some(row) = rows.next()? {
1763                v.push(row.get(0)?);
1764            }
1765
1766            assert_eq!(v, [2i32, 1]);
1767        }
1768        Ok(())
1769    }
1770
1771    #[test]
1772    fn test_query_map() -> Result<()> {
1773        let db = Connection::open_in_memory()?;
1774        let sql = "BEGIN;
1775                   CREATE TABLE foo(x INTEGER, y TEXT);
1776                   INSERT INTO foo VALUES(4, \"hello\");
1777                   INSERT INTO foo VALUES(3, \", \");
1778                   INSERT INTO foo VALUES(2, \"world\");
1779                   INSERT INTO foo VALUES(1, \"!\");
1780                   END;";
1781        db.execute_batch(sql)?;
1782
1783        let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1784        let results: Result<Vec<String>> = query.query([])?.map(|row| row.get(1)).collect();
1785
1786        assert_eq!(results?.concat(), "hello, world!");
1787        Ok(())
1788    }
1789
1790    #[test]
1791    fn test_query_row() -> Result<()> {
1792        let db = Connection::open_in_memory()?;
1793        let sql = "BEGIN;
1794                   CREATE TABLE foo(x INTEGER);
1795                   INSERT INTO foo VALUES(1);
1796                   INSERT INTO foo VALUES(2);
1797                   INSERT INTO foo VALUES(3);
1798                   INSERT INTO foo VALUES(4);
1799                   END;";
1800        db.execute_batch(sql)?;
1801
1802        assert_eq!(10, db.one_column::<i64, _>("SELECT SUM(x) FROM foo", [])?);
1803
1804        let result: Result<i64> = db.one_column("SELECT x FROM foo WHERE x > 5", []);
1805        match result.unwrap_err() {
1806            Error::QueryReturnedNoRows => (),
1807            err => panic!("Unexpected error {err}"),
1808        }
1809
1810        db.query_row("NOT A PROPER QUERY; test123", [], |_| Ok(()))
1811            .unwrap_err();
1812
1813        db.query_row("SELECT 1; SELECT 2;", [], |_| Ok(()))
1814            .unwrap_err();
1815
1816        Ok(())
1817    }
1818
1819    #[test]
1820    fn test_optional() -> Result<()> {
1821        let db = Connection::open_in_memory()?;
1822
1823        let result: Result<i64> = db.one_column("SELECT 1 WHERE 0 <> 0", []);
1824        let result = result.optional();
1825        match result? {
1826            None => (),
1827            _ => panic!("Unexpected result"),
1828        }
1829
1830        let result: Result<i64> = db.one_column("SELECT 1 WHERE 0 == 0", []);
1831        let result = result.optional();
1832        match result? {
1833            Some(1) => (),
1834            _ => panic!("Unexpected result"),
1835        }
1836
1837        let bad_query_result: Result<i64> = db.one_column("NOT A PROPER QUERY", []);
1838        let bad_query_result = bad_query_result.optional();
1839        bad_query_result.unwrap_err();
1840        Ok(())
1841    }
1842
1843    #[test]
1844    fn test_pragma_query_row() -> Result<()> {
1845        let db = Connection::open_in_memory()?;
1846        assert_eq!(
1847            "memory",
1848            db.pragma_query_one::<String>(None, "journal_mode")?
1849        );
1850        let mode = db.one_column::<String, _>("PRAGMA journal_mode=off", [])?;
1851        if cfg!(feature = "bundled") {
1852            assert_eq!(mode, "off");
1853        } else {
1854            // Note: system SQLite on macOS defaults to "off" rather than
1855            // "memory" for the journal mode (which cannot be changed for
1856            // in-memory connections). This seems like it's *probably* legal
1857            // according to the docs below, so we relax this test when not
1858            // bundling:
1859            //
1860            // From https://www.sqlite.org/pragma.html#pragma_journal_mode
1861            // > Note that the journal_mode for an in-memory database is either
1862            // > MEMORY or OFF and can not be changed to a different value. An
1863            // > attempt to change the journal_mode of an in-memory database to
1864            // > any setting other than MEMORY or OFF is ignored.
1865            assert!(mode == "memory" || mode == "off", "Got mode {mode:?}");
1866        }
1867
1868        Ok(())
1869    }
1870
1871    #[test]
1872    fn test_prepare_failures() -> Result<()> {
1873        let db = Connection::open_in_memory()?;
1874        db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1875
1876        let err = db.prepare("SELECT * FROM does_not_exist").unwrap_err();
1877        assert!(format!("{err}").contains("does_not_exist"));
1878        Ok(())
1879    }
1880
1881    #[test]
1882    fn test_last_insert_rowid() -> Result<()> {
1883        let db = Connection::open_in_memory()?;
1884        db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)")?;
1885        db.execute_batch("INSERT INTO foo DEFAULT VALUES")?;
1886
1887        assert_eq!(db.last_insert_rowid(), 1);
1888
1889        let mut stmt = db.prepare("INSERT INTO foo DEFAULT VALUES")?;
1890        for _ in 0i32..9 {
1891            stmt.execute([])?;
1892        }
1893        assert_eq!(db.last_insert_rowid(), 10);
1894        Ok(())
1895    }
1896
1897    #[test]
1898    fn test_total_changes() -> Result<()> {
1899        let db = Connection::open_in_memory()?;
1900        let sql = "CREATE TABLE foo(x INTEGER PRIMARY KEY, value TEXT default '' NOT NULL,
1901                                    desc TEXT default '');
1902                   CREATE VIEW foo_bar AS SELECT x, desc FROM foo WHERE value = 'bar';
1903                   CREATE TRIGGER INSERT_FOOBAR
1904                   INSTEAD OF INSERT
1905                   ON foo_bar
1906                   BEGIN
1907                       INSERT INTO foo VALUES(new.x, 'bar', new.desc);
1908                   END;";
1909        db.execute_batch(sql)?;
1910        let total_changes_before = db.total_changes();
1911        let changes = db
1912            .prepare("INSERT INTO foo_bar VALUES(null, 'baz');")?
1913            .execute([])?;
1914        let total_changes_after = db.total_changes();
1915        assert_eq!(changes, 0);
1916        assert_eq!(total_changes_after - total_changes_before, 1);
1917        Ok(())
1918    }
1919
1920    #[test]
1921    fn test_is_autocommit() -> Result<()> {
1922        let db = Connection::open_in_memory()?;
1923        assert!(
1924            db.is_autocommit(),
1925            "autocommit expected to be active by default"
1926        );
1927        Ok(())
1928    }
1929
1930    #[test]
1931    fn test_is_busy() -> Result<()> {
1932        let db = Connection::open_in_memory()?;
1933        assert!(!db.is_busy());
1934        let mut stmt = db.prepare("PRAGMA schema_version")?;
1935        assert!(!db.is_busy());
1936        {
1937            let mut rows = stmt.query([])?;
1938            assert!(!db.is_busy());
1939            let row = rows.next()?;
1940            assert!(db.is_busy());
1941            assert!(row.is_some());
1942        }
1943        assert!(!db.is_busy());
1944        Ok(())
1945    }
1946
1947    #[test]
1948    fn test_statement_debugging() -> Result<()> {
1949        let db = Connection::open_in_memory()?;
1950        let query = "SELECT 12345";
1951        let stmt = db.prepare(query)?;
1952
1953        assert!(format!("{stmt:?}").contains(query));
1954        Ok(())
1955    }
1956
1957    #[test]
1958    fn test_notnull_constraint_error() -> Result<()> {
1959        let db = Connection::open_in_memory()?;
1960        db.execute_batch("CREATE TABLE foo(x NOT NULL)")?;
1961
1962        let result = db.execute("INSERT INTO foo (x) VALUES (NULL)", []);
1963
1964        assert_matches!(
1965            result.unwrap_err(),
1966            Error::SqliteFailure(
1967                ffi::Error {
1968                    code: ErrorCode::ConstraintViolation,
1969                    extended_code: ffi::SQLITE_CONSTRAINT_NOTNULL
1970                },
1971                _
1972            )
1973        );
1974        Ok(())
1975    }
1976
1977    #[test]
1978    fn test_version_string() {
1979        let n = version_number();
1980        let major = n / 1_000_000;
1981        let minor = (n % 1_000_000) / 1_000;
1982        let patch = n % 1_000;
1983
1984        assert!(version().contains(&format!("{major}.{minor}.{patch}")));
1985    }
1986
1987    #[test]
1988    #[cfg(feature = "functions")]
1989    fn test_interrupt() -> Result<()> {
1990        let db = Connection::open_in_memory()?;
1991
1992        let interrupt_handle = db.get_interrupt_handle();
1993
1994        db.create_scalar_function(
1995            "interrupt",
1996            0,
1997            functions::FunctionFlags::default(),
1998            move |_| {
1999                interrupt_handle.interrupt();
2000                Ok(0)
2001            },
2002        )?;
2003
2004        let mut stmt =
2005            db.prepare("SELECT interrupt() FROM (SELECT 1 UNION SELECT 2 UNION SELECT 3)")?;
2006
2007        let result: Result<Vec<i32>> = stmt.query([])?.map(|r| r.get(0)).collect();
2008
2009        assert_eq!(
2010            result.unwrap_err().sqlite_error_code(),
2011            Some(ErrorCode::OperationInterrupted)
2012        );
2013        Ok(())
2014    }
2015
2016    #[test]
2017    fn test_interrupt_close() {
2018        let db = checked_memory_handle();
2019        let handle = db.get_interrupt_handle();
2020        handle.interrupt();
2021        db.close().unwrap();
2022        handle.interrupt();
2023
2024        // Look at its internals to see if we cleared it out properly.
2025        let db_guard = handle.db_lock.lock().unwrap();
2026        assert!(db_guard.is_null());
2027        // It would be nice to test that we properly handle close/interrupt
2028        // running at the same time, but it seems impossible to do with any
2029        // degree of reliability.
2030    }
2031
2032    #[test]
2033    fn test_get_raw() -> Result<()> {
2034        let db = Connection::open_in_memory()?;
2035        db.execute_batch("CREATE TABLE foo(i, x);")?;
2036        let vals = ["foobar", "1234", "qwerty"];
2037        let mut insert_stmt = db.prepare("INSERT INTO foo(i, x) VALUES(?1, ?2)")?;
2038        for (i, v) in vals.iter().enumerate() {
2039            let i_to_insert = i as i64;
2040            assert_eq!(insert_stmt.execute(params![i_to_insert, v])?, 1);
2041        }
2042
2043        let mut query = db.prepare("SELECT i, x FROM foo")?;
2044        let mut rows = query.query([])?;
2045
2046        while let Some(row) = rows.next()? {
2047            let i = row.get_ref(0)?.as_i64()?;
2048            let expect = vals[i as usize];
2049            let x = row.get_ref("x")?.as_str()?;
2050            assert_eq!(x, expect);
2051        }
2052
2053        let mut query = db.prepare("SELECT x FROM foo")?;
2054        let rows = query.query_map([], |row| {
2055            let x = row.get_ref(0)?.as_str()?; // check From<FromSqlError> for Error
2056            Ok(x[..].to_owned())
2057        })?;
2058
2059        for (i, row) in rows.enumerate() {
2060            assert_eq!(row?, vals[i]);
2061        }
2062        Ok(())
2063    }
2064
2065    #[test]
2066    fn test_from_handle() -> Result<()> {
2067        let db = Connection::open_in_memory()?;
2068        let handle = unsafe { db.handle() };
2069        {
2070            let db = unsafe { Connection::from_handle(handle) }?;
2071            db.execute_batch("PRAGMA VACUUM")?;
2072        }
2073        db.close().unwrap();
2074        Ok(())
2075    }
2076
2077    #[test]
2078    fn test_from_handle_owned() -> Result<()> {
2079        let mut handle: *mut ffi::sqlite3 = std::ptr::null_mut();
2080        let r = unsafe { ffi::sqlite3_open(c":memory:".as_ptr(), &mut handle) };
2081        assert_eq!(r, ffi::SQLITE_OK);
2082        let db = unsafe { Connection::from_handle_owned(handle) }?;
2083        db.execute_batch("PRAGMA VACUUM")?;
2084        Ok(())
2085    }
2086
2087    mod query_and_then_tests {
2088        #[cfg(all(target_family = "wasm", target_os = "unknown"))]
2089        use wasm_bindgen_test::wasm_bindgen_test as test;
2090
2091        use super::*;
2092
2093        #[derive(Debug)]
2094        enum CustomError {
2095            SomeError,
2096            Sqlite(Error),
2097        }
2098
2099        impl fmt::Display for CustomError {
2100            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
2101                match *self {
2102                    Self::SomeError => write!(f, "my custom error"),
2103                    Self::Sqlite(ref se) => write!(f, "my custom error: {se}"),
2104                }
2105            }
2106        }
2107
2108        impl StdError for CustomError {
2109            fn description(&self) -> &str {
2110                "my custom error"
2111            }
2112
2113            fn cause(&self) -> Option<&dyn StdError> {
2114                match *self {
2115                    Self::SomeError => None,
2116                    Self::Sqlite(ref se) => Some(se),
2117                }
2118            }
2119        }
2120
2121        impl From<Error> for CustomError {
2122            fn from(se: Error) -> Self {
2123                Self::Sqlite(se)
2124            }
2125        }
2126
2127        type CustomResult<T> = Result<T, CustomError>;
2128
2129        #[test]
2130        fn test_query_and_then() -> Result<()> {
2131            let db = Connection::open_in_memory()?;
2132            let sql = "BEGIN;
2133                       CREATE TABLE foo(x INTEGER, y TEXT);
2134                       INSERT INTO foo VALUES(4, \"hello\");
2135                       INSERT INTO foo VALUES(3, \", \");
2136                       INSERT INTO foo VALUES(2, \"world\");
2137                       INSERT INTO foo VALUES(1, \"!\");
2138                       END;";
2139            db.execute_batch(sql)?;
2140
2141            let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
2142            let results: Result<Vec<String>> =
2143                query.query_and_then([], |row| row.get(1))?.collect();
2144
2145            assert_eq!(results?.concat(), "hello, world!");
2146            Ok(())
2147        }
2148
2149        #[test]
2150        fn test_query_and_then_fails() -> Result<()> {
2151            let db = Connection::open_in_memory()?;
2152            let sql = "BEGIN;
2153                       CREATE TABLE foo(x INTEGER, y TEXT);
2154                       INSERT INTO foo VALUES(4, \"hello\");
2155                       INSERT INTO foo VALUES(3, \", \");
2156                       INSERT INTO foo VALUES(2, \"world\");
2157                       INSERT INTO foo VALUES(1, \"!\");
2158                       END;";
2159            db.execute_batch(sql)?;
2160
2161            let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
2162            let bad_type: Result<Vec<f64>> = query.query_and_then([], |row| row.get(1))?.collect();
2163
2164            match bad_type.unwrap_err() {
2165                Error::InvalidColumnType(..) => (),
2166                err => panic!("Unexpected error {err}"),
2167            }
2168
2169            let bad_idx: Result<Vec<String>> =
2170                query.query_and_then([], |row| row.get(3))?.collect();
2171
2172            match bad_idx.unwrap_err() {
2173                Error::InvalidColumnIndex(_) => (),
2174                err => panic!("Unexpected error {err}"),
2175            }
2176            Ok(())
2177        }
2178
2179        #[test]
2180        fn test_query_and_then_custom_error() -> CustomResult<()> {
2181            let db = Connection::open_in_memory()?;
2182            let sql = "BEGIN;
2183                       CREATE TABLE foo(x INTEGER, y TEXT);
2184                       INSERT INTO foo VALUES(4, \"hello\");
2185                       INSERT INTO foo VALUES(3, \", \");
2186                       INSERT INTO foo VALUES(2, \"world\");
2187                       INSERT INTO foo VALUES(1, \"!\");
2188                       END;";
2189            db.execute_batch(sql)?;
2190
2191            let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
2192            let results: CustomResult<Vec<String>> = query
2193                .query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite))?
2194                .collect();
2195
2196            assert_eq!(results?.concat(), "hello, world!");
2197            Ok(())
2198        }
2199
2200        #[test]
2201        fn test_query_and_then_custom_error_fails() -> Result<()> {
2202            let db = Connection::open_in_memory()?;
2203            let sql = "BEGIN;
2204                       CREATE TABLE foo(x INTEGER, y TEXT);
2205                       INSERT INTO foo VALUES(4, \"hello\");
2206                       INSERT INTO foo VALUES(3, \", \");
2207                       INSERT INTO foo VALUES(2, \"world\");
2208                       INSERT INTO foo VALUES(1, \"!\");
2209                       END;";
2210            db.execute_batch(sql)?;
2211
2212            let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
2213            let bad_type: CustomResult<Vec<f64>> = query
2214                .query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite))?
2215                .collect();
2216
2217            match bad_type.unwrap_err() {
2218                CustomError::Sqlite(Error::InvalidColumnType(..)) => (),
2219                err => panic!("Unexpected error {err}"),
2220            }
2221
2222            let bad_idx: CustomResult<Vec<String>> = query
2223                .query_and_then([], |row| row.get(3).map_err(CustomError::Sqlite))?
2224                .collect();
2225
2226            match bad_idx.unwrap_err() {
2227                CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
2228                err => panic!("Unexpected error {err}"),
2229            }
2230
2231            let non_sqlite_err: CustomResult<Vec<String>> = query
2232                .query_and_then([], |_| Err(CustomError::SomeError))?
2233                .collect();
2234
2235            match non_sqlite_err.unwrap_err() {
2236                CustomError::SomeError => (),
2237                err => panic!("Unexpected error {err}"),
2238            }
2239            Ok(())
2240        }
2241
2242        #[test]
2243        fn test_query_row_and_then_custom_error() -> CustomResult<()> {
2244            let db = Connection::open_in_memory()?;
2245            let sql = "BEGIN;
2246                       CREATE TABLE foo(x INTEGER, y TEXT);
2247                       INSERT INTO foo VALUES(4, \"hello\");
2248                       END;";
2249            db.execute_batch(sql)?;
2250
2251            let query = "SELECT x, y FROM foo ORDER BY x DESC";
2252            let results: CustomResult<String> =
2253                db.query_row_and_then(query, [], |row| row.get(1).map_err(CustomError::Sqlite));
2254
2255            assert_eq!(results?, "hello");
2256            Ok(())
2257        }
2258
2259        #[test]
2260        fn test_query_row_and_then_custom_error_fails() -> Result<()> {
2261            let db = Connection::open_in_memory()?;
2262            let sql = "BEGIN;
2263                       CREATE TABLE foo(x INTEGER, y TEXT);
2264                       INSERT INTO foo VALUES(4, \"hello\");
2265                       END;";
2266            db.execute_batch(sql)?;
2267
2268            let query = "SELECT x, y FROM foo ORDER BY x DESC";
2269            let bad_type: CustomResult<f64> =
2270                db.query_row_and_then(query, [], |row| row.get(1).map_err(CustomError::Sqlite));
2271
2272            match bad_type.unwrap_err() {
2273                CustomError::Sqlite(Error::InvalidColumnType(..)) => (),
2274                err => panic!("Unexpected error {err}"),
2275            }
2276
2277            let bad_idx: CustomResult<String> =
2278                db.query_row_and_then(query, [], |row| row.get(3).map_err(CustomError::Sqlite));
2279
2280            match bad_idx.unwrap_err() {
2281                CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
2282                err => panic!("Unexpected error {err}"),
2283            }
2284
2285            let non_sqlite_err: CustomResult<String> =
2286                db.query_row_and_then(query, [], |_| Err(CustomError::SomeError));
2287
2288            match non_sqlite_err.unwrap_err() {
2289                CustomError::SomeError => (),
2290                err => panic!("Unexpected error {err}"),
2291            }
2292            Ok(())
2293        }
2294    }
2295
2296    #[test]
2297    fn test_dynamic() -> Result<()> {
2298        let db = Connection::open_in_memory()?;
2299        let sql = "BEGIN;
2300                       CREATE TABLE foo(x INTEGER, y TEXT);
2301                       INSERT INTO foo VALUES(4, \"hello\");
2302                       END;";
2303        db.execute_batch(sql)?;
2304
2305        db.query_row("SELECT * FROM foo", [], |r| {
2306            assert_eq!(2, r.as_ref().column_count());
2307            Ok(())
2308        })
2309    }
2310    #[test]
2311    fn test_dyn_box() -> Result<()> {
2312        let db = Connection::open_in_memory()?;
2313        db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
2314        let b: Box<dyn ToSql> = Box::new(5);
2315        db.execute("INSERT INTO foo VALUES(?1)", [b])?;
2316        db.query_row("SELECT x FROM foo", [], |r| {
2317            assert_eq!(5, r.get_unwrap::<_, i32>(0));
2318            Ok(())
2319        })
2320    }
2321
2322    #[test]
2323    fn test_params() -> Result<()> {
2324        let db = Connection::open_in_memory()?;
2325        db.query_row(
2326            "SELECT
2327            ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10,
2328            ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19, ?20,
2329            ?21, ?22, ?23, ?24, ?25, ?26, ?27, ?28, ?29, ?30,
2330            ?31, ?32, ?33, ?34;",
2331            params![
2332                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2333                1, 1, 1, 1, 1, 1,
2334            ],
2335            |r| {
2336                assert_eq!(1, r.get_unwrap::<_, i32>(0));
2337                Ok(())
2338            },
2339        )
2340    }
2341
2342    #[test]
2343    fn test_alter_table() -> Result<()> {
2344        let db = Connection::open_in_memory()?;
2345        db.execute_batch("CREATE TABLE x(t);")?;
2346        // `execute_batch` should be used but `execute` should also work
2347        db.execute("ALTER TABLE x RENAME TO y;", [])?;
2348        Ok(())
2349    }
2350
2351    #[test]
2352    fn test_batch() -> Result<()> {
2353        let db = Connection::open_in_memory()?;
2354        let sql = r"
2355             CREATE TABLE tbl1 (col);
2356             CREATE TABLE tbl2 (col);
2357             ";
2358        let mut batch = Batch::new(&db, sql);
2359        while let Some(mut stmt) = batch.next()? {
2360            stmt.execute([])?;
2361        }
2362        Ok(())
2363    }
2364
2365    #[test]
2366    fn test_invalid_batch() -> Result<()> {
2367        let db = Connection::open_in_memory()?;
2368        let sql = r"
2369            PRAGMA test1;
2370            PRAGMA test2=?;
2371            PRAGMA test3;
2372            ";
2373        let mut batch = Batch::new(&db, sql);
2374        assert!(batch.next().is_ok());
2375        assert!(batch.next().is_err());
2376        assert!(batch.next().is_err());
2377        assert!(Batch::new(&db, sql).count().is_err());
2378        Ok(())
2379    }
2380
2381    #[test]
2382    fn test_returning() -> Result<()> {
2383        let db = Connection::open_in_memory()?;
2384        db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)")?;
2385        let row_id =
2386            db.one_column::<i64, _>("INSERT INTO foo DEFAULT VALUES RETURNING ROWID", [])?;
2387        assert_eq!(row_id, 1);
2388        Ok(())
2389    }
2390
2391    #[test]
2392    fn test_cache_flush() -> Result<()> {
2393        let db = Connection::open_in_memory()?;
2394        db.cache_flush()
2395    }
2396
2397    #[test]
2398    fn db_readonly() -> Result<()> {
2399        let db = Connection::open_in_memory()?;
2400        assert!(!db.is_readonly(MAIN_DB)?);
2401        Ok(())
2402    }
2403
2404    #[test]
2405    #[cfg(feature = "rusqlite-macros")]
2406    fn prepare_and_bind() -> Result<()> {
2407        let db = Connection::open_in_memory()?;
2408        let name = "Lisa";
2409        let age = 8;
2410        let mut stmt = prepare_and_bind!(db, "SELECT $name, $age;");
2411        let (v1, v2) = stmt
2412            .raw_query()
2413            .next()
2414            .and_then(|o| o.ok_or(Error::QueryReturnedNoRows))
2415            .and_then(|r| Ok((r.get::<_, String>(0)?, r.get::<_, i64>(1)?)))?;
2416        assert_eq!((v1.as_str(), v2), (name, age));
2417        Ok(())
2418    }
2419
2420    #[test]
2421    fn test_db_name() -> Result<()> {
2422        let db = Connection::open_in_memory()?;
2423        assert_eq!(db.db_name(0)?, "main");
2424        assert_eq!(db.db_name(1)?, "temp");
2425        assert_eq!(db.db_name(2), Err(Error::InvalidDatabaseIndex(2)));
2426        db.execute_batch("ATTACH DATABASE ':memory:' AS xyz;")?;
2427        assert_eq!(db.db_name(2)?, "xyz");
2428        Ok(())
2429    }
2430
2431    #[test]
2432    fn test_is_interrupted() -> Result<()> {
2433        let db = Connection::open_in_memory()?;
2434        assert!(!db.is_interrupted());
2435        db.get_interrupt_handle().interrupt();
2436        assert!(db.is_interrupted());
2437        Ok(())
2438    }
2439
2440    #[test]
2441    fn release_memory() -> Result<()> {
2442        let db = Connection::open_in_memory()?;
2443        db.release_memory()
2444    }
2445
2446    #[test]
2447    fn client_data() -> Result<()> {
2448        let db = Connection::open_in_memory()?;
2449        let name = c"my_data";
2450        {
2451            unsafe { db.set_clientdata(name, None::<c_void>)? };
2452        }
2453        {
2454            let data = "my_value".to_owned();
2455            unsafe { db.set_clientdata(name, Some(data))? };
2456        }
2457        {
2458            if let Some(data) = unsafe { db.get_clientdata::<String, _>(name) }? {
2459                assert_eq!(*data, "my_value");
2460            }
2461        }
2462        Ok(())
2463    }
2464
2465    #[test]
2466    #[cfg(feature = "modern_sqlite")] // 3.51.0
2467    fn set_errmsg() -> Result<()> {
2468        let db = Connection::open_in_memory()?;
2469        let code: i32 = ffi::SQLITE_MISUSE;
2470        let msg = c"Oops";
2471        db.set_errmsg(code, Some(msg))?;
2472        let ptr = unsafe { db.handle() };
2473        assert_eq!(unsafe { ffi::sqlite3_errcode(ptr) }, code);
2474        assert_eq!(unsafe { CStr::from_ptr(ffi::sqlite3_errmsg(ptr)) }, msg);
2475        Ok(())
2476    }
2477
2478    #[cfg_attr(
2479        all(target_family = "wasm", target_os = "unknown"),
2480        ignore = "no filesystem on this platform"
2481    )]
2482    #[test]
2483    fn file_control() -> Result<()> {
2484        let temp_dir = tempfile::tempdir().unwrap();
2485        let path = temp_dir.path().join("file_control.db3");
2486        let db = Connection::open(&path)?;
2487
2488        let mut size = 20971520;
2489        db.file_control(DEFAULT_NAME, FileControl::SizeHint(&mut size))?;
2490
2491        let mut size = -1;
2492        assert_matches!(
2493            db.file_control(DEFAULT_NAME, FileControl::SizeLimit(&mut size),),
2494            Err(Error::SqliteFailure(
2495                ffi::Error {
2496                    code: ErrorCode::NotFound,
2497                    extended_code: ffi::SQLITE_NOTFOUND,
2498                },
2499                None
2500            ))
2501        );
2502
2503        let mut size = 32768;
2504        db.file_control(DEFAULT_NAME, FileControl::ChunkSize(&mut size))?;
2505
2506        let mut persist_wal = -1;
2507        db.file_control(DEFAULT_NAME, FileControl::PersistWal(&mut persist_wal))?;
2508        assert_ne!(persist_wal, -1);
2509        persist_wal = 1;
2510        db.file_control(DEFAULT_NAME, FileControl::PersistWal(&mut persist_wal))?;
2511
2512        let mut psow = -1;
2513        db.file_control(DEFAULT_NAME, FileControl::PowerSafeOverwrite(&mut psow))?;
2514        assert_ne!(psow, -1);
2515
2516        let mut mmap_size = -1;
2517        db.file_control(DEFAULT_NAME, FileControl::MMapSize(&mut mmap_size))?;
2518        assert_ne!(mmap_size, -1);
2519
2520        #[cfg(unix)]
2521        {
2522            let mut has_moved = -1;
2523            db.file_control(DEFAULT_NAME, FileControl::HasMoved(&mut has_moved))?;
2524            assert_ne!(has_moved, -1);
2525        }
2526
2527        #[cfg(feature = "modern_sqlite")]
2528        {
2529            let mut boc = 1;
2530            db.file_control(DEFAULT_NAME, FileControl::BlockOnConnect(&mut boc))
2531                .unwrap_err();
2532        }
2533
2534        let mut data_version = 0;
2535        db.file_control(DEFAULT_NAME, FileControl::DataVersion(&mut data_version))?;
2536        assert_ne!(data_version, 0);
2537
2538        let mut reserve_bytes = -1;
2539        db.file_control(DEFAULT_NAME, FileControl::ReserveBytes(&mut reserve_bytes))?;
2540        assert_ne!(reserve_bytes, -1);
2541
2542        Ok(())
2543    }
2544
2545    #[test]
2546    #[cfg(feature = "bundled-sqlcipher")]
2547    fn bundled_sqlcipher() -> Result<()> {
2548        let db = checked_memory_handle();
2549        let version: String = db.pragma_query_one(None, "cipher_version")?;
2550        assert!(!version.is_empty());
2551
2552        let temp_dir = tempfile::tempdir().unwrap();
2553        let path = temp_dir.path().join("test.db3");
2554        {
2555            let db = Connection::open(&path)?;
2556            db.pragma_update(None, "key", "secret")?;
2557            db.execute_batch("CREATE TABLE foo(x TEXT);")?;
2558            db.execute("INSERT INTO foo VALUES(?1)", ["plaintext"])?;
2559        }
2560        let bytes = std::fs::read(&path).unwrap();
2561        assert!(!bytes.windows(9).any(|w| w == b"plaintext"));
2562        for key in ["", "PRAGMA key = 'wrong'"] {
2563            let db = Connection::open(&path)?;
2564            db.execute_batch(key)?;
2565            assert_eq!(
2566                db.one_column::<String, _>("SELECT x FROM foo", [])
2567                    .unwrap_err()
2568                    .sqlite_error_code(),
2569                Some(ErrorCode::NotADatabase)
2570            );
2571        }
2572        let db = Connection::open(&path)?;
2573        db.pragma_update(None, "key", "secret")?;
2574        assert_eq!(
2575            db.one_column::<String, _>("SELECT x FROM foo", [])?,
2576            "plaintext"
2577        );
2578        Ok(())
2579    }
2580}