1#![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#[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#[cfg(feature = "cache")]
171const STATEMENT_CACHE_DEFAULT_CAPACITY: usize = 16;
172
173#[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#[macro_export]
233macro_rules! named_params {
234 () => {
235 &[] as &[(&str, &dyn $crate::ToSql)]
236 };
237 ($($param_name:literal: $param_val:expr),+ $(,)?) => {
240 &[$(($param_name, &$param_val as &dyn $crate::ToSql)),+] as &[(&str, &dyn $crate::ToSql)]
241 };
242}
243
244#[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#[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
287pub type Result<T, E = Error> = result::Result<T, E>;
289
290pub trait OptionalExtension<T> {
292 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
321fn 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 ("".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
356pub const MAIN_DB: &CStr = c"main";
358pub const DEFAULT_NAME: Option<&'static str> = None;
360pub const TEMP_DB: &CStr = c"temp";
362
363pub 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 #[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 #[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 #[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 #[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 #[inline]
517 pub fn open_in_memory_with_flags(flags: OpenFlags) -> Result<Self> {
518 Self::open_with_flags(":memory:", flags)
519 }
520
521 #[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 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 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 #[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 #[inline]
641 pub fn path(&self) -> Option<&str> {
642 unsafe { inner_connection::db_filename(std::marker::PhantomData, self.handle(), MAIN_DB) }
643 }
644
645 #[inline]
650 pub fn release_memory(&self) -> Result<()> {
651 self.db.borrow_mut().release_memory()
652 }
653
654 #[inline]
659 pub fn last_insert_rowid(&self) -> i64 {
660 self.db.borrow_mut().last_insert_rowid()
661 }
662
663 #[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 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 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 #[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 #[inline]
789 pub fn prepare(&self, sql: &str) -> Result<Statement<'_>> {
790 self.prepare_with_flags(sql, PrepFlags::default())
791 }
792
793 #[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 #[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 #[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 #[cfg(feature = "load_extension")]
893 #[inline]
894 pub fn load_extension_disable(&self) -> Result<()> {
895 unsafe { self.db.borrow_mut().enable_load_extension(0) }
897 }
898
899 #[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 #[inline]
962 pub unsafe fn handle(&self) -> *mut ffi::sqlite3 {
963 self.db.borrow().db()
964 }
965
966 #[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 #[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 #[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 #[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 #[inline]
1054 pub fn changes(&self) -> u64 {
1055 self.db.borrow().changes()
1056 }
1057
1058 #[inline]
1064 pub fn total_changes(&self) -> u64 {
1065 self.db.borrow().total_changes()
1066 }
1067
1068 #[inline]
1071 pub fn is_autocommit(&self) -> bool {
1072 self.db.borrow().is_autocommit()
1073 }
1074
1075 #[inline]
1077 pub fn is_busy(&self) -> bool {
1078 self.db.borrow().is_busy()
1079 }
1080
1081 pub fn cache_flush(&self) -> Result<()> {
1083 self.db.borrow_mut().cache_flush()
1084 }
1085
1086 pub fn is_readonly<N: Name>(&self, db_name: N) -> Result<bool> {
1088 self.db.borrow().db_readonly(db_name)
1089 }
1090
1091 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 pub fn is_interrupted(&self) -> bool {
1110 self.db.borrow().is_interrupted()
1111 }
1112
1113 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 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 #[cfg(feature = "modern_sqlite")] pub fn set_errmsg(&self, code: c_int, msg: Option<&CStr>) -> Result<()> {
1143 unsafe { error::set_errmsg(self.handle(), code, msg) }
1144 }
1145
1146 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#[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 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 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 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1256 #[repr(C)]
1257 pub struct OpenFlags: c_int {
1258 const SQLITE_OPEN_READ_ONLY = ffi::SQLITE_OPEN_READONLY;
1261 const SQLITE_OPEN_READ_WRITE = ffi::SQLITE_OPEN_READWRITE;
1265 const SQLITE_OPEN_CREATE = ffi::SQLITE_OPEN_CREATE;
1267 const SQLITE_OPEN_URI = ffi::SQLITE_OPEN_URI;
1269 const SQLITE_OPEN_MEMORY = ffi::SQLITE_OPEN_MEMORY;
1271 const SQLITE_OPEN_NO_MUTEX = ffi::SQLITE_OPEN_NOMUTEX;
1280 const SQLITE_OPEN_FULL_MUTEX = ffi::SQLITE_OPEN_FULLMUTEX;
1304 const SQLITE_OPEN_SHARED_CACHE = 0x0002_0000;
1311 const SQLITE_OPEN_PRIVATE_CACHE = 0x0004_0000;
1313 const SQLITE_OPEN_NOFOLLOW = 0x0100_0000;
1315 const SQLITE_OPEN_EXRESCODE = 0x0200_0000;
1317 }
1318}
1319
1320impl Default for OpenFlags {
1321 #[inline]
1322 fn default() -> Self {
1323 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 #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
1336 #[repr(C)]
1337 pub struct PrepFlags: c_uint {
1338 const SQLITE_PREPARE_PERSISTENT = 0x01;
1340 const SQLITE_PREPARE_NO_VTAB = 0x04;
1342 const SQLITE_PREPARE_DONT_LOG = 0x10;
1344 const SQLITE_PREPARE_FROM_DDL = 0x20; }
1348}
1349
1350pub 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 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#[derive(Debug)]
1373#[non_exhaustive]
1374pub enum FileControl<'p> {
1375 SizeHint(&'p mut ffi::sqlite3_int64),
1379 SizeLimit(&'p mut ffi::sqlite3_int64),
1381 ChunkSize(&'p mut c_int),
1383 PersistWal(&'p mut c_int),
1385 PowerSafeOverwrite(&'p mut c_int),
1387 MMapSize(&'p mut ffi::sqlite3_int64),
1389 #[cfg(unix)]
1391 HasMoved(&'p mut c_int),
1392 LockTimeout(&'p mut c_int),
1394 #[cfg(feature = "modern_sqlite")]
1396 BlockOnConnect(&'p mut c_int),
1397 DataVersion(&'p mut c_uint),
1399 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 #[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 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 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 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 let (db, _) = db.close().unwrap_err();
1611 let (db, _) = db.close().unwrap_err();
1612 let (db, _) = db.close().unwrap_err();
1613
1614 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 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 let db_guard = handle.db_lock.lock().unwrap();
2026 assert!(db_guard.is_null());
2027 }
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()?; 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 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")] 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}