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(target_family = "wasm", target_os = "unknown")))]
61pub use libsqlite3_sys as ffi;
62#[cfg(all(target_family = "wasm", target_os = "unknown"))]
63pub use sqlite_wasm_rs as ffi;
64
65use std::cell::RefCell;
66use std::default::Default;
67use std::ffi::{c_char, c_int, c_uint, CStr, CString};
68use std::fmt;
69
70use std::path::Path;
71use std::result;
72use std::str;
73use std::sync::{Arc, Mutex};
74
75#[cfg(feature = "cache")]
76use crate::cache::StatementCache;
77use crate::inner_connection::InnerConnection;
78use crate::raw_statement::RawStatement;
79use crate::types::ValueRef;
80
81pub use crate::bind::BindIndex;
82#[cfg(feature = "cache")]
83pub use crate::cache::CachedStatement;
84#[cfg(feature = "column_decltype")]
85pub use crate::column::Column;
86#[cfg(feature = "column_metadata")]
87pub use crate::column::ColumnMetadata;
88pub use crate::error::{to_sqlite_error, Error};
89pub use crate::ffi::ErrorCode;
90#[cfg(feature = "load_extension")]
91pub use crate::load_extension_guard::LoadExtensionGuard;
92pub use crate::params::{params_from_iter, Params, ParamsFromIter};
93pub use crate::row::{AndThenRows, Map, MappedRows, Row, RowIndex, Rows};
94pub use crate::statement::{Statement, StatementStatus};
95#[cfg(feature = "modern_sqlite")]
96pub use crate::transaction::TransactionState;
97pub use crate::transaction::{DropBehavior, Savepoint, Transaction, TransactionBehavior};
98pub use crate::types::ToSql;
99pub use crate::util::Name;
100pub use crate::version::*;
101#[cfg(feature = "rusqlite-macros")]
102#[doc(hidden)]
103pub use rusqlite_macros::__bind;
104
105#[macro_use]
106mod error;
107
108#[cfg(not(feature = "loadable_extension"))]
109pub mod auto_extension;
110#[cfg(feature = "backup")]
111pub mod backup;
112mod bind;
113#[cfg(feature = "blob")]
114pub mod blob;
115mod busy;
116#[cfg(feature = "cache")]
117mod cache;
118#[cfg(feature = "collation")]
119mod collation;
120mod column;
121pub mod config;
122#[cfg(any(feature = "functions", feature = "vtab"))]
123mod context;
124#[cfg(feature = "functions")]
125pub mod functions;
126#[cfg(feature = "hooks")]
127pub mod hooks;
128mod inner_connection;
129#[cfg(feature = "limits")]
130pub mod limits;
131#[cfg(feature = "load_extension")]
132mod load_extension_guard;
133mod params;
134mod pragma;
135mod raw_statement;
136mod row;
137#[cfg(feature = "serialize")]
138pub mod serialize;
139#[cfg(feature = "session")]
140pub mod session;
141mod statement;
142#[cfg(feature = "trace")]
143pub mod trace;
144mod transaction;
145pub mod types;
146#[cfg(feature = "unlock_notify")]
147mod unlock_notify;
148mod version;
149#[cfg(feature = "vtab")]
150pub mod vtab;
151
152pub(crate) mod util;
153
154#[cfg(all(feature = "loadable_extension", feature = "load_extension"))]
156compile_error!("feature \"loadable_extension\" and feature \"load_extension\" cannot be enabled at the same time");
157
158#[cfg(feature = "cache")]
160const STATEMENT_CACHE_DEFAULT_CAPACITY: usize = 16;
161
162#[macro_export]
185macro_rules! params {
186 () => {
187 &[] as &[&dyn $crate::ToSql]
188 };
189 ($($param:expr),+ $(,)?) => {
190 &[$(&$param as &dyn $crate::ToSql),+] as &[&dyn $crate::ToSql]
191 };
192}
193
194#[macro_export]
222macro_rules! named_params {
223 () => {
224 &[] as &[(&str, &dyn $crate::ToSql)]
225 };
226 ($($param_name:literal: $param_val:expr),+ $(,)?) => {
229 &[$(($param_name, &$param_val as &dyn $crate::ToSql)),+] as &[(&str, &dyn $crate::ToSql)]
230 };
231}
232
233#[cfg(feature = "rusqlite-macros")]
252#[macro_export]
253macro_rules! prepare_and_bind {
254 ($conn:expr, $sql:literal) => {{
255 let mut stmt = $conn.prepare($sql)?;
256 $crate::__bind!(stmt $sql);
257 stmt
258 }};
259}
260
261#[cfg(feature = "rusqlite-macros")]
267#[macro_export]
268macro_rules! prepare_cached_and_bind {
269 ($conn:expr, $sql:literal) => {{
270 let mut stmt = $conn.prepare_cached($sql)?;
271 $crate::__bind!(stmt $sql);
272 stmt
273 }};
274}
275
276pub type Result<T, E = Error> = result::Result<T, E>;
278
279pub trait OptionalExtension<T> {
281 fn optional(self) -> Result<Option<T>>;
287}
288
289impl<T> OptionalExtension<T> for Result<T> {
290 fn optional(self) -> Result<Option<T>> {
291 match self {
292 Ok(value) => Ok(Some(value)),
293 Err(Error::QueryReturnedNoRows) => Ok(None),
294 Err(e) => Err(e),
295 }
296 }
297}
298
299unsafe fn errmsg_to_string(errmsg: *const c_char) -> String {
300 CStr::from_ptr(errmsg).to_string_lossy().into_owned()
301}
302
303#[cfg(any(feature = "functions", feature = "vtab", test))]
304fn str_to_cstring(s: &str) -> Result<util::SmallCString> {
305 Ok(util::SmallCString::new(s)?)
306}
307
308fn str_for_sqlite(
314 s: &[u8],
315) -> (
316 *const c_char,
317 ffi::sqlite3_uint64,
318 ffi::sqlite3_destructor_type,
319) {
320 let len = s.len();
321 let (ptr, dtor_info) = if len != 0 {
322 (s.as_ptr().cast::<c_char>(), ffi::SQLITE_TRANSIENT())
323 } else {
324 ("".as_ptr().cast::<c_char>(), ffi::SQLITE_STATIC())
326 };
327 (ptr, len as ffi::sqlite3_uint64, dtor_info)
328}
329
330#[cfg(unix)]
331fn path_to_cstring(p: &Path) -> Result<CString> {
332 use std::os::unix::ffi::OsStrExt;
333 Ok(CString::new(p.as_os_str().as_bytes())?)
334}
335
336#[cfg(not(unix))]
337fn path_to_cstring(p: &Path) -> Result<CString> {
338 let s = p.to_str().ok_or_else(|| Error::InvalidPath(p.to_owned()))?;
339 Ok(CString::new(s)?)
340}
341
342pub const MAIN_DB: &CStr = c"main";
344pub const TEMP_DB: &CStr = c"temp";
346
347pub struct Connection {
349 db: RefCell<InnerConnection>,
350 #[cfg(feature = "cache")]
351 cache: StatementCache,
352 transaction_behavior: TransactionBehavior,
353}
354
355unsafe impl Send for Connection {}
356
357impl Drop for Connection {
358 #[inline]
359 fn drop(&mut self) {
360 #[cfg(feature = "cache")]
361 self.flush_prepared_statement_cache();
362 }
363}
364
365impl Connection {
366 #[inline]
428 pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
429 let flags = OpenFlags::default();
430 Self::open_with_flags(path, flags)
431 }
432
433 #[inline]
439 pub fn open_in_memory() -> Result<Self> {
440 let flags = OpenFlags::default();
441 Self::open_in_memory_with_flags(flags)
442 }
443
444 #[inline]
454 pub fn open_with_flags<P: AsRef<Path>>(path: P, flags: OpenFlags) -> Result<Self> {
455 let c_path = path_to_cstring(path.as_ref())?;
456 InnerConnection::open_with_flags(&c_path, flags, None).map(|db| Self {
457 db: RefCell::new(db),
458 #[cfg(feature = "cache")]
459 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
460 transaction_behavior: TransactionBehavior::Deferred,
461 })
462 }
463
464 #[inline]
475 pub fn open_with_flags_and_vfs<P: AsRef<Path>, V: Name>(
476 path: P,
477 flags: OpenFlags,
478 vfs: V,
479 ) -> Result<Self> {
480 let c_path = path_to_cstring(path.as_ref())?;
481 let c_vfs = vfs.as_cstr()?;
482 InnerConnection::open_with_flags(&c_path, flags, Some(&c_vfs)).map(|db| Self {
483 db: RefCell::new(db),
484 #[cfg(feature = "cache")]
485 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
486 transaction_behavior: TransactionBehavior::Deferred,
487 })
488 }
489
490 #[inline]
499 pub fn open_in_memory_with_flags(flags: OpenFlags) -> Result<Self> {
500 Self::open_with_flags(":memory:", flags)
501 }
502
503 #[inline]
514 pub fn open_in_memory_with_flags_and_vfs<V: Name>(flags: OpenFlags, vfs: V) -> Result<Self> {
515 Self::open_with_flags_and_vfs(":memory:", flags, vfs)
516 }
517
518 pub fn execute_batch(&self, sql: &str) -> Result<()> {
540 let mut sql = sql;
541 while !sql.is_empty() {
542 let (stmt, tail) = self
543 .db
544 .borrow_mut()
545 .prepare(self, sql, PrepFlags::default())?;
546 if !stmt.stmt.is_null() && stmt.step()? {
547 if false {
549 return Err(Error::ExecuteReturnedResults);
550 }
551 }
552 if tail == 0 || tail >= sql.len() {
553 break;
554 }
555 sql = &sql[tail..];
556 }
557 Ok(())
558 }
559
560 #[inline]
611 pub fn execute<P: Params>(&self, sql: &str, params: P) -> Result<usize> {
612 self.prepare(sql).and_then(|mut stmt| stmt.execute(params))
613 }
614
615 #[inline]
623 pub fn path(&self) -> Option<&str> {
624 unsafe {
625 crate::inner_connection::db_filename(std::marker::PhantomData, self.handle(), MAIN_DB)
626 }
627 }
628
629 #[inline]
634 pub fn release_memory(&self) -> Result<()> {
635 self.db.borrow_mut().release_memory()
636 }
637
638 #[inline]
643 pub fn last_insert_rowid(&self) -> i64 {
644 self.db.borrow_mut().last_insert_rowid()
645 }
646
647 #[inline]
675 pub fn query_row<T, P, F>(&self, sql: &str, params: P, f: F) -> Result<T>
676 where
677 P: Params,
678 F: FnOnce(&Row<'_>) -> Result<T>,
679 {
680 let mut stmt = self.prepare(sql)?;
681 stmt.query_row(params, f)
682 }
683
684 pub fn query_one<T, P, F>(&self, sql: &str, params: P, f: F) -> Result<T>
699 where
700 P: Params,
701 F: FnOnce(&Row<'_>) -> Result<T>,
702 {
703 let mut stmt = self.prepare(sql)?;
704 stmt.query_one(params, f)
705 }
706
707 #[cfg(test)]
709 pub(crate) fn one_column<T, P>(&self, sql: &str, params: P) -> Result<T>
710 where
711 T: types::FromSql,
712 P: Params,
713 {
714 self.query_one(sql, params, |r| r.get(0))
715 }
716
717 #[inline]
743 pub fn query_row_and_then<T, E, P, F>(&self, sql: &str, params: P, f: F) -> Result<T, E>
744 where
745 P: Params,
746 F: FnOnce(&Row<'_>) -> Result<T, E>,
747 E: From<Error>,
748 {
749 let mut stmt = self.prepare(sql)?;
750 let mut rows = stmt.query(params)?;
751
752 rows.get_expected_row().map_err(E::from).and_then(f)
753 }
754
755 #[inline]
774 pub fn prepare(&self, sql: &str) -> Result<Statement<'_>> {
775 self.prepare_with_flags(sql, PrepFlags::default())
776 }
777
778 #[inline]
785 pub fn prepare_with_flags(&self, sql: &str, flags: PrepFlags) -> Result<Statement<'_>> {
786 let (stmt, tail) = self.db.borrow_mut().prepare(self, sql, flags)?;
787 if tail != 0 && !self.prepare(&sql[tail..])?.stmt.is_null() {
788 Err(Error::MultipleStatement)
789 } else {
790 Ok(stmt)
791 }
792 }
793
794 #[expect(clippy::result_large_err)]
804 #[inline]
805 pub fn close(self) -> Result<(), (Self, Error)> {
806 #[cfg(feature = "cache")]
807 self.flush_prepared_statement_cache();
808 let r = self.db.borrow_mut().close();
809 r.map_err(move |err| (self, err))
810 }
811
812 #[cfg(feature = "load_extension")]
865 #[inline]
866 pub unsafe fn load_extension_enable(&self) -> Result<()> {
867 self.db.borrow_mut().enable_load_extension(1)
868 }
869
870 #[cfg(feature = "load_extension")]
878 #[inline]
879 pub fn load_extension_disable(&self) -> Result<()> {
880 unsafe { self.db.borrow_mut().enable_load_extension(0) }
882 }
883
884 #[cfg(feature = "load_extension")]
920 #[inline]
921 pub unsafe fn load_extension<P: AsRef<Path>, N: Name>(
922 &self,
923 dylib_path: P,
924 entry_point: Option<N>,
925 ) -> Result<()> {
926 self.db
927 .borrow_mut()
928 .load_extension(dylib_path.as_ref(), entry_point)
929 }
930
931 #[inline]
945 pub unsafe fn handle(&self) -> *mut ffi::sqlite3 {
946 self.db.borrow().db()
947 }
948
949 #[inline]
958 pub unsafe fn from_handle(db: *mut ffi::sqlite3) -> Result<Self> {
959 let db = InnerConnection::new(db, false);
960 Ok(Self {
961 db: RefCell::new(db),
962 #[cfg(feature = "cache")]
963 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
964 transaction_behavior: TransactionBehavior::Deferred,
965 })
966 }
967
968 #[cfg(feature = "loadable_extension")]
974 pub unsafe fn extension_init2(
975 db: *mut ffi::sqlite3,
976 pz_err_msg: *mut *mut c_char,
977 p_api: *mut ffi::sqlite3_api_routines,
978 init: fn(Self) -> Result<bool>,
979 ) -> c_int {
980 if p_api.is_null() {
981 return ffi::SQLITE_ERROR;
982 }
983 match ffi::rusqlite_extension_init2(p_api)
984 .map_err(Error::from)
985 .and(Self::from_handle(db))
986 .and_then(init)
987 {
988 Err(err) => to_sqlite_error(&err, pz_err_msg),
989 Ok(true) => ffi::SQLITE_OK_LOAD_PERMANENTLY,
990 _ => ffi::SQLITE_OK,
991 }
992 }
993
994 #[inline]
1007 pub unsafe fn from_handle_owned(db: *mut ffi::sqlite3) -> Result<Self> {
1008 let db = InnerConnection::new(db, true);
1009 Ok(Self {
1010 db: RefCell::new(db),
1011 #[cfg(feature = "cache")]
1012 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
1013 transaction_behavior: TransactionBehavior::Deferred,
1014 })
1015 }
1016
1017 #[inline]
1020 pub fn get_interrupt_handle(&self) -> InterruptHandle {
1021 self.db.borrow().get_interrupt_handle()
1022 }
1023
1024 #[inline]
1025 fn decode_result(&self, code: c_int) -> Result<()> {
1026 self.db.borrow().decode_result(code)
1027 }
1028
1029 #[inline]
1035 pub fn changes(&self) -> u64 {
1036 self.db.borrow().changes()
1037 }
1038
1039 #[inline]
1045 pub fn total_changes(&self) -> u64 {
1046 self.db.borrow().total_changes()
1047 }
1048
1049 #[inline]
1052 pub fn is_autocommit(&self) -> bool {
1053 self.db.borrow().is_autocommit()
1054 }
1055
1056 #[inline]
1058 pub fn is_busy(&self) -> bool {
1059 self.db.borrow().is_busy()
1060 }
1061
1062 pub fn cache_flush(&self) -> Result<()> {
1064 self.db.borrow_mut().cache_flush()
1065 }
1066
1067 pub fn is_readonly<N: Name>(&self, db_name: N) -> Result<bool> {
1069 self.db.borrow().db_readonly(db_name)
1070 }
1071
1072 #[cfg(feature = "modern_sqlite")] pub fn db_name(&self, index: usize) -> Result<String> {
1079 unsafe {
1080 let db = self.handle();
1081 let name = ffi::sqlite3_db_name(db, index as c_int);
1082 if name.is_null() {
1083 Err(Error::InvalidDatabaseIndex(index))
1084 } else {
1085 Ok(CStr::from_ptr(name).to_str()?.to_owned())
1086 }
1087 }
1088 }
1089
1090 #[cfg(feature = "modern_sqlite")] pub fn is_interrupted(&self) -> bool {
1093 self.db.borrow().is_interrupted()
1094 }
1095}
1096
1097impl fmt::Debug for Connection {
1098 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1099 f.debug_struct("Connection")
1100 .field("path", &self.path())
1101 .finish()
1102 }
1103}
1104
1105#[derive(Debug)]
1130pub struct Batch<'conn, 'sql> {
1131 conn: &'conn Connection,
1132 sql: &'sql str,
1133 tail: usize,
1134}
1135
1136impl<'conn, 'sql> Batch<'conn, 'sql> {
1137 pub fn new(conn: &'conn Connection, sql: &'sql str) -> Self {
1139 Batch { conn, sql, tail: 0 }
1140 }
1141}
1142impl<'conn> fallible_iterator::FallibleIterator for Batch<'conn, '_> {
1143 type Error = Error;
1144 type Item = Statement<'conn>;
1145
1146 fn next(&mut self) -> Result<Option<Statement<'conn>>> {
1150 while self.tail < self.sql.len() {
1151 let sql = &self.sql[self.tail..];
1152 let (next, tail) =
1153 self.conn
1154 .db
1155 .borrow_mut()
1156 .prepare(self.conn, sql, PrepFlags::default())?;
1157 if tail == 0 {
1158 self.tail = self.sql.len();
1159 } else {
1160 self.tail += tail;
1161 }
1162 if next.stmt.is_null() {
1163 continue;
1164 }
1165 return Ok(Some(next));
1166 }
1167 Ok(None)
1168 }
1169}
1170
1171bitflags::bitflags! {
1172 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1179 #[repr(C)]
1180 pub struct OpenFlags: c_int {
1181 const SQLITE_OPEN_READ_ONLY = ffi::SQLITE_OPEN_READONLY;
1184 const SQLITE_OPEN_READ_WRITE = ffi::SQLITE_OPEN_READWRITE;
1188 const SQLITE_OPEN_CREATE = ffi::SQLITE_OPEN_CREATE;
1190 const SQLITE_OPEN_URI = ffi::SQLITE_OPEN_URI;
1192 const SQLITE_OPEN_MEMORY = ffi::SQLITE_OPEN_MEMORY;
1194 const SQLITE_OPEN_NO_MUTEX = ffi::SQLITE_OPEN_NOMUTEX;
1203 const SQLITE_OPEN_FULL_MUTEX = ffi::SQLITE_OPEN_FULLMUTEX;
1227 const SQLITE_OPEN_SHARED_CACHE = 0x0002_0000;
1234 const SQLITE_OPEN_PRIVATE_CACHE = 0x0004_0000;
1236 const SQLITE_OPEN_NOFOLLOW = 0x0100_0000;
1238 const SQLITE_OPEN_EXRESCODE = 0x0200_0000;
1240 }
1241}
1242
1243impl Default for OpenFlags {
1244 #[inline]
1245 fn default() -> Self {
1246 Self::SQLITE_OPEN_READ_WRITE
1249 | Self::SQLITE_OPEN_CREATE
1250 | Self::SQLITE_OPEN_NO_MUTEX
1251 | Self::SQLITE_OPEN_URI
1252 }
1253}
1254
1255bitflags::bitflags! {
1256 #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
1259 #[repr(C)]
1260 pub struct PrepFlags: c_uint {
1261 const SQLITE_PREPARE_PERSISTENT = 0x01;
1263 const SQLITE_PREPARE_NO_VTAB = 0x04;
1265 const SQLITE_PREPARE_DONT_LOG = 0x10;
1267 }
1268}
1269
1270pub struct InterruptHandle {
1272 db_lock: Arc<Mutex<*mut ffi::sqlite3>>,
1273}
1274
1275unsafe impl Send for InterruptHandle {}
1276unsafe impl Sync for InterruptHandle {}
1277
1278impl InterruptHandle {
1279 pub fn interrupt(&self) {
1282 let db_handle = self.db_lock.lock().unwrap();
1283 if !db_handle.is_null() {
1284 unsafe { ffi::sqlite3_interrupt(*db_handle) }
1285 }
1286 }
1287}
1288
1289#[cfg(doctest)]
1290doc_comment::doctest!("../README.md");
1291
1292#[cfg(test)]
1293mod test {
1294 #[cfg(all(target_family = "wasm", target_os = "unknown"))]
1295 use wasm_bindgen_test::wasm_bindgen_test as test;
1296
1297 use super::*;
1298 use fallible_iterator::FallibleIterator;
1299 use std::error::Error as StdError;
1300 use std::fmt;
1301
1302 #[allow(dead_code)]
1306 #[expect(unconditional_recursion, clippy::extra_unused_type_parameters)]
1307 fn ensure_send<T: Send>() {
1308 ensure_send::<Connection>();
1309 ensure_send::<InterruptHandle>();
1310 }
1311
1312 #[allow(dead_code)]
1313 #[expect(unconditional_recursion, clippy::extra_unused_type_parameters)]
1314 fn ensure_sync<T: Sync>() {
1315 ensure_sync::<InterruptHandle>();
1316 }
1317
1318 fn checked_memory_handle() -> Connection {
1319 Connection::open_in_memory().unwrap()
1320 }
1321
1322 #[cfg_attr(
1323 all(target_family = "wasm", target_os = "unknown"),
1324 ignore = "no filesystem on this platform"
1325 )]
1326 #[test]
1327 fn test_concurrent_transactions_busy_commit() -> Result<()> {
1328 use std::time::Duration;
1329 let tmp = tempfile::tempdir().unwrap();
1330 let path = tmp.path().join("transactions.db3");
1331
1332 Connection::open(&path)?.execute_batch(
1333 "
1334 BEGIN; CREATE TABLE foo(x INTEGER);
1335 INSERT INTO foo VALUES(42); END;",
1336 )?;
1337
1338 let mut db1 = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_WRITE)?;
1339 let mut db2 = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_ONLY)?;
1340
1341 db1.busy_timeout(Duration::from_millis(0))?;
1342 db2.busy_timeout(Duration::from_millis(0))?;
1343
1344 {
1345 let tx1 = db1.transaction()?;
1346 let tx2 = db2.transaction()?;
1347
1348 tx1.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))?;
1350 tx2.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))?;
1351
1352 tx1.execute("INSERT INTO foo VALUES(?1)", [1])?;
1353 let _ = tx2.execute("INSERT INTO foo VALUES(?1)", [2]);
1354
1355 let _ = tx1.commit();
1356 let _ = tx2.commit();
1357 }
1358
1359 let _ = db1
1360 .transaction()
1361 .expect("commit should have closed transaction");
1362 let _ = db2
1363 .transaction()
1364 .expect("commit should have closed transaction");
1365 Ok(())
1366 }
1367
1368 #[cfg_attr(
1369 all(target_family = "wasm", target_os = "unknown"),
1370 ignore = "no filesystem on this platform"
1371 )]
1372 #[test]
1373 fn test_persistence() -> Result<()> {
1374 let temp_dir = tempfile::tempdir().unwrap();
1375 let path = temp_dir.path().join("test.db3");
1376
1377 {
1378 let db = Connection::open(&path)?;
1379 let sql = "BEGIN;
1380 CREATE TABLE foo(x INTEGER);
1381 INSERT INTO foo VALUES(42);
1382 END;";
1383 db.execute_batch(sql)?;
1384 }
1385
1386 let path_string = path.to_str().unwrap();
1387 let db = Connection::open(path_string)?;
1388
1389 assert_eq!(42, db.one_column::<i64, _>("SELECT x FROM foo", [])?);
1390 Ok(())
1391 }
1392
1393 #[test]
1394 fn test_open() {
1395 Connection::open_in_memory().unwrap();
1396
1397 let db = checked_memory_handle();
1398 db.close().unwrap();
1399 }
1400
1401 #[cfg_attr(
1402 all(target_family = "wasm", target_os = "unknown"),
1403 ignore = "no filesystem on this platform"
1404 )]
1405 #[test]
1406 fn test_path() -> Result<()> {
1407 let tmp = tempfile::tempdir().unwrap();
1408 let db = Connection::open("")?;
1409 assert_eq!(Some(""), db.path());
1410 let db = Connection::open_in_memory()?;
1411 assert_eq!(Some(""), db.path());
1412 let db = Connection::open("file:dummy.db?mode=memory&cache=shared")?;
1413 assert_eq!(Some(""), db.path());
1414 let path = tmp.path().join("file.db");
1415 let db = Connection::open(path)?;
1416 assert!(db.path().is_some_and(|p| p.ends_with("file.db")));
1417 Ok(())
1418 }
1419
1420 #[test]
1421 fn test_open_failure() {
1422 let filename = "no_such_file.db";
1423 let result = Connection::open_with_flags(filename, OpenFlags::SQLITE_OPEN_READ_ONLY);
1424 let err = result.unwrap_err();
1425 if let Error::SqliteFailure(e, Some(msg)) = err {
1426 assert_eq!(ErrorCode::CannotOpen, e.code);
1427 assert_eq!(ffi::SQLITE_CANTOPEN, e.extended_code);
1428 assert!(
1429 msg.contains(filename),
1430 "error message '{msg}' does not contain '{filename}'"
1431 );
1432 } else {
1433 panic!("SqliteFailure expected");
1434 }
1435 }
1436
1437 #[cfg(unix)]
1438 #[test]
1439 fn test_invalid_unicode_file_names() -> Result<()> {
1440 use std::ffi::OsStr;
1441 use std::fs::File;
1442 use std::os::unix::ffi::OsStrExt;
1443 let temp_dir = tempfile::tempdir().unwrap();
1444
1445 let path = temp_dir.path();
1446 if File::create(path.join(OsStr::from_bytes(&[0xFE]))).is_err() {
1447 return Ok(());
1449 }
1450 let db_path = path.join(OsStr::from_bytes(&[0xFF]));
1451 {
1452 let db = Connection::open(&db_path)?;
1453 let sql = "BEGIN;
1454 CREATE TABLE foo(x INTEGER);
1455 INSERT INTO foo VALUES(42);
1456 END;";
1457 db.execute_batch(sql)?;
1458 }
1459
1460 let db = Connection::open(&db_path)?;
1461
1462 assert_eq!(42, db.one_column::<i64, _>("SELECT x FROM foo", [])?);
1463 Ok(())
1464 }
1465
1466 #[test]
1467 fn test_close_retry() -> Result<()> {
1468 let db = Connection::open_in_memory()?;
1469
1470 let raw_stmt = {
1474 use super::str_to_cstring;
1475 use std::ffi::c_int;
1476 use std::ptr;
1477
1478 let raw_db = db.db.borrow_mut().db;
1479 let sql = "SELECT 1";
1480 let mut raw_stmt: *mut ffi::sqlite3_stmt = ptr::null_mut();
1481 let cstring = str_to_cstring(sql)?;
1482 let rc = unsafe {
1483 ffi::sqlite3_prepare_v2(
1484 raw_db,
1485 cstring.as_ptr(),
1486 (sql.len() + 1) as c_int,
1487 &mut raw_stmt,
1488 ptr::null_mut(),
1489 )
1490 };
1491 assert_eq!(rc, ffi::SQLITE_OK);
1492 raw_stmt
1493 };
1494
1495 let (db, _) = db.close().unwrap_err();
1498 let (db, _) = db.close().unwrap_err();
1499 let (db, _) = db.close().unwrap_err();
1500
1501 assert_eq!(ffi::SQLITE_OK, unsafe { ffi::sqlite3_finalize(raw_stmt) });
1503
1504 db.close().unwrap();
1505 Ok(())
1506 }
1507
1508 #[test]
1509 fn test_open_with_flags() {
1510 for bad_flags in &[
1511 OpenFlags::empty(),
1512 OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_READ_WRITE,
1513 OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_CREATE,
1514 ] {
1515 Connection::open_in_memory_with_flags(*bad_flags).unwrap_err();
1516 }
1517 }
1518
1519 #[test]
1520 fn test_execute_batch() -> Result<()> {
1521 let db = Connection::open_in_memory()?;
1522 let sql = "BEGIN;
1523 CREATE TABLE foo(x INTEGER);
1524 INSERT INTO foo VALUES(1);
1525 INSERT INTO foo VALUES(2);
1526 INSERT INTO foo VALUES(3);
1527 INSERT INTO foo VALUES(4);
1528 END;";
1529 db.execute_batch(sql)?;
1530
1531 db.execute_batch("UPDATE foo SET x = 3 WHERE x < 3")?;
1532
1533 db.execute_batch("INVALID SQL").unwrap_err();
1534
1535 db.execute_batch("PRAGMA locking_mode = EXCLUSIVE")?;
1536 Ok(())
1537 }
1538
1539 #[test]
1540 fn test_execute() -> Result<()> {
1541 let db = Connection::open_in_memory()?;
1542 db.execute_batch("CREATE TABLE foo(x INTEGER)")?;
1543
1544 assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?1)", [1i32])?);
1545 assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?1)", [2i32])?);
1546
1547 assert_eq!(3, db.one_column::<i32, _>("SELECT SUM(x) FROM foo", [])?);
1548 Ok(())
1549 }
1550
1551 #[test]
1552 #[cfg(feature = "extra_check")]
1553 fn test_execute_select_with_no_row() {
1554 let db = checked_memory_handle();
1555 let err = db.execute("SELECT 1 WHERE 1 < ?1", [1i32]).unwrap_err();
1556 assert_eq!(
1557 err,
1558 Error::ExecuteReturnedResults,
1559 "Unexpected error: {err}"
1560 );
1561 }
1562
1563 #[test]
1564 fn test_execute_select_with_row() {
1565 let db = checked_memory_handle();
1566 let err = db.execute("SELECT 1", []).unwrap_err();
1567 assert_eq!(err, Error::ExecuteReturnedResults);
1568 }
1569
1570 #[test]
1571 fn test_execute_multiple() {
1572 let db = checked_memory_handle();
1573 let err = db
1574 .execute(
1575 "CREATE TABLE foo(x INTEGER); CREATE TABLE foo(x INTEGER)",
1576 [],
1577 )
1578 .unwrap_err();
1579 match err {
1580 Error::MultipleStatement => (),
1581 _ => panic!("Unexpected error: {err}"),
1582 }
1583 db.execute("CREATE TABLE t(c); -- bim", [])
1584 .expect("Tail comment should be ignored");
1585 }
1586
1587 #[test]
1588 fn test_prepare_column_names() -> Result<()> {
1589 let db = Connection::open_in_memory()?;
1590 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1591
1592 let stmt = db.prepare("SELECT * FROM foo")?;
1593 assert_eq!(stmt.column_count(), 1);
1594 assert_eq!(stmt.column_names(), vec!["x"]);
1595
1596 let stmt = db.prepare("SELECT x AS a, x AS b FROM foo")?;
1597 assert_eq!(stmt.column_count(), 2);
1598 assert_eq!(stmt.column_names(), vec!["a", "b"]);
1599 Ok(())
1600 }
1601
1602 #[test]
1603 fn test_prepare_execute() -> Result<()> {
1604 let db = Connection::open_in_memory()?;
1605 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1606
1607 let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?1)")?;
1608 assert_eq!(insert_stmt.execute([1i32])?, 1);
1609 assert_eq!(insert_stmt.execute([2i32])?, 1);
1610 assert_eq!(insert_stmt.execute([3i32])?, 1);
1611
1612 assert_eq!(insert_stmt.execute(["hello"])?, 1);
1613 assert_eq!(insert_stmt.execute(["goodbye"])?, 1);
1614 assert_eq!(insert_stmt.execute([types::Null])?, 1);
1615
1616 let mut update_stmt = db.prepare("UPDATE foo SET x=?1 WHERE x<?2")?;
1617 assert_eq!(update_stmt.execute([3i32, 3i32])?, 2);
1618 assert_eq!(update_stmt.execute([3i32, 3i32])?, 0);
1619 assert_eq!(update_stmt.execute([8i32, 8i32])?, 3);
1620 Ok(())
1621 }
1622
1623 #[test]
1624 fn test_prepare_query() -> Result<()> {
1625 let db = Connection::open_in_memory()?;
1626 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1627
1628 let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?1)")?;
1629 assert_eq!(insert_stmt.execute([1i32])?, 1);
1630 assert_eq!(insert_stmt.execute([2i32])?, 1);
1631 assert_eq!(insert_stmt.execute([3i32])?, 1);
1632
1633 let mut query = db.prepare("SELECT x FROM foo WHERE x < ?1 ORDER BY x DESC")?;
1634 {
1635 let mut rows = query.query([4i32])?;
1636 let mut v = Vec::<i32>::new();
1637
1638 while let Some(row) = rows.next()? {
1639 v.push(row.get(0)?);
1640 }
1641
1642 assert_eq!(v, [3i32, 2, 1]);
1643 }
1644
1645 {
1646 let mut rows = query.query([3i32])?;
1647 let mut v = Vec::<i32>::new();
1648
1649 while let Some(row) = rows.next()? {
1650 v.push(row.get(0)?);
1651 }
1652
1653 assert_eq!(v, [2i32, 1]);
1654 }
1655 Ok(())
1656 }
1657
1658 #[test]
1659 fn test_query_map() -> Result<()> {
1660 let db = Connection::open_in_memory()?;
1661 let sql = "BEGIN;
1662 CREATE TABLE foo(x INTEGER, y TEXT);
1663 INSERT INTO foo VALUES(4, \"hello\");
1664 INSERT INTO foo VALUES(3, \", \");
1665 INSERT INTO foo VALUES(2, \"world\");
1666 INSERT INTO foo VALUES(1, \"!\");
1667 END;";
1668 db.execute_batch(sql)?;
1669
1670 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1671 let results: Result<Vec<String>> = query.query([])?.map(|row| row.get(1)).collect();
1672
1673 assert_eq!(results?.concat(), "hello, world!");
1674 Ok(())
1675 }
1676
1677 #[test]
1678 fn test_query_row() -> Result<()> {
1679 let db = Connection::open_in_memory()?;
1680 let sql = "BEGIN;
1681 CREATE TABLE foo(x INTEGER);
1682 INSERT INTO foo VALUES(1);
1683 INSERT INTO foo VALUES(2);
1684 INSERT INTO foo VALUES(3);
1685 INSERT INTO foo VALUES(4);
1686 END;";
1687 db.execute_batch(sql)?;
1688
1689 assert_eq!(10, db.one_column::<i64, _>("SELECT SUM(x) FROM foo", [])?);
1690
1691 let result: Result<i64> = db.one_column("SELECT x FROM foo WHERE x > 5", []);
1692 match result.unwrap_err() {
1693 Error::QueryReturnedNoRows => (),
1694 err => panic!("Unexpected error {err}"),
1695 }
1696
1697 db.query_row("NOT A PROPER QUERY; test123", [], |_| Ok(()))
1698 .unwrap_err();
1699
1700 db.query_row("SELECT 1; SELECT 2;", [], |_| Ok(()))
1701 .unwrap_err();
1702
1703 Ok(())
1704 }
1705
1706 #[test]
1707 fn test_optional() -> Result<()> {
1708 let db = Connection::open_in_memory()?;
1709
1710 let result: Result<i64> = db.one_column("SELECT 1 WHERE 0 <> 0", []);
1711 let result = result.optional();
1712 match result? {
1713 None => (),
1714 _ => panic!("Unexpected result"),
1715 }
1716
1717 let result: Result<i64> = db.one_column("SELECT 1 WHERE 0 == 0", []);
1718 let result = result.optional();
1719 match result? {
1720 Some(1) => (),
1721 _ => panic!("Unexpected result"),
1722 }
1723
1724 let bad_query_result: Result<i64> = db.one_column("NOT A PROPER QUERY", []);
1725 let bad_query_result = bad_query_result.optional();
1726 bad_query_result.unwrap_err();
1727 Ok(())
1728 }
1729
1730 #[test]
1731 fn test_pragma_query_row() -> Result<()> {
1732 let db = Connection::open_in_memory()?;
1733 assert_eq!(
1734 "memory",
1735 db.one_column::<String, _>("PRAGMA journal_mode", [])?
1736 );
1737 let mode = db.one_column::<String, _>("PRAGMA journal_mode=off", [])?;
1738 if cfg!(feature = "bundled") {
1739 assert_eq!(mode, "off");
1740 } else {
1741 assert!(mode == "memory" || mode == "off", "Got mode {mode:?}");
1753 }
1754
1755 Ok(())
1756 }
1757
1758 #[test]
1759 fn test_prepare_failures() -> Result<()> {
1760 let db = Connection::open_in_memory()?;
1761 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1762
1763 let err = db.prepare("SELECT * FROM does_not_exist").unwrap_err();
1764 assert!(format!("{err}").contains("does_not_exist"));
1765 Ok(())
1766 }
1767
1768 #[test]
1769 fn test_last_insert_rowid() -> Result<()> {
1770 let db = Connection::open_in_memory()?;
1771 db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)")?;
1772 db.execute_batch("INSERT INTO foo DEFAULT VALUES")?;
1773
1774 assert_eq!(db.last_insert_rowid(), 1);
1775
1776 let mut stmt = db.prepare("INSERT INTO foo DEFAULT VALUES")?;
1777 for _ in 0i32..9 {
1778 stmt.execute([])?;
1779 }
1780 assert_eq!(db.last_insert_rowid(), 10);
1781 Ok(())
1782 }
1783
1784 #[test]
1785 fn test_total_changes() -> Result<()> {
1786 let db = Connection::open_in_memory()?;
1787 let sql = "CREATE TABLE foo(x INTEGER PRIMARY KEY, value TEXT default '' NOT NULL,
1788 desc TEXT default '');
1789 CREATE VIEW foo_bar AS SELECT x, desc FROM foo WHERE value = 'bar';
1790 CREATE TRIGGER INSERT_FOOBAR
1791 INSTEAD OF INSERT
1792 ON foo_bar
1793 BEGIN
1794 INSERT INTO foo VALUES(new.x, 'bar', new.desc);
1795 END;";
1796 db.execute_batch(sql)?;
1797 let total_changes_before = db.total_changes();
1798 let changes = db
1799 .prepare("INSERT INTO foo_bar VALUES(null, 'baz');")?
1800 .execute([])?;
1801 let total_changes_after = db.total_changes();
1802 assert_eq!(changes, 0);
1803 assert_eq!(total_changes_after - total_changes_before, 1);
1804 Ok(())
1805 }
1806
1807 #[test]
1808 fn test_is_autocommit() -> Result<()> {
1809 let db = Connection::open_in_memory()?;
1810 assert!(
1811 db.is_autocommit(),
1812 "autocommit expected to be active by default"
1813 );
1814 Ok(())
1815 }
1816
1817 #[test]
1818 fn test_is_busy() -> Result<()> {
1819 let db = Connection::open_in_memory()?;
1820 assert!(!db.is_busy());
1821 let mut stmt = db.prepare("PRAGMA schema_version")?;
1822 assert!(!db.is_busy());
1823 {
1824 let mut rows = stmt.query([])?;
1825 assert!(!db.is_busy());
1826 let row = rows.next()?;
1827 assert!(db.is_busy());
1828 assert!(row.is_some());
1829 }
1830 assert!(!db.is_busy());
1831 Ok(())
1832 }
1833
1834 #[test]
1835 fn test_statement_debugging() -> Result<()> {
1836 let db = Connection::open_in_memory()?;
1837 let query = "SELECT 12345";
1838 let stmt = db.prepare(query)?;
1839
1840 assert!(format!("{stmt:?}").contains(query));
1841 Ok(())
1842 }
1843
1844 #[test]
1845 fn test_notnull_constraint_error() -> Result<()> {
1846 let db = Connection::open_in_memory()?;
1847 db.execute_batch("CREATE TABLE foo(x NOT NULL)")?;
1848
1849 let result = db.execute("INSERT INTO foo (x) VALUES (NULL)", []);
1850
1851 match result.unwrap_err() {
1852 Error::SqliteFailure(err, _) => {
1853 assert_eq!(err.code, ErrorCode::ConstraintViolation);
1854 assert_eq!(err.extended_code, ffi::SQLITE_CONSTRAINT_NOTNULL);
1855 }
1856 err => panic!("Unexpected error {err}"),
1857 }
1858 Ok(())
1859 }
1860
1861 #[test]
1862 fn test_version_string() {
1863 let n = version_number();
1864 let major = n / 1_000_000;
1865 let minor = (n % 1_000_000) / 1_000;
1866 let patch = n % 1_000;
1867
1868 assert!(version().contains(&format!("{major}.{minor}.{patch}")));
1869 }
1870
1871 #[test]
1872 #[cfg(feature = "functions")]
1873 fn test_interrupt() -> Result<()> {
1874 let db = Connection::open_in_memory()?;
1875
1876 let interrupt_handle = db.get_interrupt_handle();
1877
1878 db.create_scalar_function(
1879 "interrupt",
1880 0,
1881 functions::FunctionFlags::default(),
1882 move |_| {
1883 interrupt_handle.interrupt();
1884 Ok(0)
1885 },
1886 )?;
1887
1888 let mut stmt =
1889 db.prepare("SELECT interrupt() FROM (SELECT 1 UNION SELECT 2 UNION SELECT 3)")?;
1890
1891 let result: Result<Vec<i32>> = stmt.query([])?.map(|r| r.get(0)).collect();
1892
1893 assert_eq!(
1894 result.unwrap_err().sqlite_error_code(),
1895 Some(ErrorCode::OperationInterrupted)
1896 );
1897 Ok(())
1898 }
1899
1900 #[test]
1901 fn test_interrupt_close() {
1902 let db = checked_memory_handle();
1903 let handle = db.get_interrupt_handle();
1904 handle.interrupt();
1905 db.close().unwrap();
1906 handle.interrupt();
1907
1908 let db_guard = handle.db_lock.lock().unwrap();
1910 assert!(db_guard.is_null());
1911 }
1915
1916 #[test]
1917 fn test_get_raw() -> Result<()> {
1918 let db = Connection::open_in_memory()?;
1919 db.execute_batch("CREATE TABLE foo(i, x);")?;
1920 let vals = ["foobar", "1234", "qwerty"];
1921 let mut insert_stmt = db.prepare("INSERT INTO foo(i, x) VALUES(?1, ?2)")?;
1922 for (i, v) in vals.iter().enumerate() {
1923 let i_to_insert = i as i64;
1924 assert_eq!(insert_stmt.execute(params![i_to_insert, v])?, 1);
1925 }
1926
1927 let mut query = db.prepare("SELECT i, x FROM foo")?;
1928 let mut rows = query.query([])?;
1929
1930 while let Some(row) = rows.next()? {
1931 let i = row.get_ref(0)?.as_i64()?;
1932 let expect = vals[i as usize];
1933 let x = row.get_ref("x")?.as_str()?;
1934 assert_eq!(x, expect);
1935 }
1936
1937 let mut query = db.prepare("SELECT x FROM foo")?;
1938 let rows = query.query_map([], |row| {
1939 let x = row.get_ref(0)?.as_str()?; Ok(x[..].to_owned())
1941 })?;
1942
1943 for (i, row) in rows.enumerate() {
1944 assert_eq!(row?, vals[i]);
1945 }
1946 Ok(())
1947 }
1948
1949 #[test]
1950 fn test_from_handle() -> Result<()> {
1951 let db = Connection::open_in_memory()?;
1952 let handle = unsafe { db.handle() };
1953 {
1954 let db = unsafe { Connection::from_handle(handle) }?;
1955 db.execute_batch("PRAGMA VACUUM")?;
1956 }
1957 db.close().unwrap();
1958 Ok(())
1959 }
1960
1961 #[test]
1962 fn test_from_handle_owned() -> Result<()> {
1963 let mut handle: *mut ffi::sqlite3 = std::ptr::null_mut();
1964 let r = unsafe { ffi::sqlite3_open(c":memory:".as_ptr(), &mut handle) };
1965 assert_eq!(r, ffi::SQLITE_OK);
1966 let db = unsafe { Connection::from_handle_owned(handle) }?;
1967 db.execute_batch("PRAGMA VACUUM")?;
1968 Ok(())
1969 }
1970
1971 mod query_and_then_tests {
1972 #[cfg(all(target_family = "wasm", target_os = "unknown"))]
1973 use wasm_bindgen_test::wasm_bindgen_test as test;
1974
1975 use super::*;
1976
1977 #[derive(Debug)]
1978 enum CustomError {
1979 SomeError,
1980 Sqlite(Error),
1981 }
1982
1983 impl fmt::Display for CustomError {
1984 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1985 match *self {
1986 Self::SomeError => write!(f, "my custom error"),
1987 Self::Sqlite(ref se) => write!(f, "my custom error: {se}"),
1988 }
1989 }
1990 }
1991
1992 impl StdError for CustomError {
1993 fn description(&self) -> &str {
1994 "my custom error"
1995 }
1996
1997 fn cause(&self) -> Option<&dyn StdError> {
1998 match *self {
1999 Self::SomeError => None,
2000 Self::Sqlite(ref se) => Some(se),
2001 }
2002 }
2003 }
2004
2005 impl From<Error> for CustomError {
2006 fn from(se: Error) -> Self {
2007 Self::Sqlite(se)
2008 }
2009 }
2010
2011 type CustomResult<T> = Result<T, CustomError>;
2012
2013 #[test]
2014 fn test_query_and_then() -> Result<()> {
2015 let db = Connection::open_in_memory()?;
2016 let sql = "BEGIN;
2017 CREATE TABLE foo(x INTEGER, y TEXT);
2018 INSERT INTO foo VALUES(4, \"hello\");
2019 INSERT INTO foo VALUES(3, \", \");
2020 INSERT INTO foo VALUES(2, \"world\");
2021 INSERT INTO foo VALUES(1, \"!\");
2022 END;";
2023 db.execute_batch(sql)?;
2024
2025 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
2026 let results: Result<Vec<String>> =
2027 query.query_and_then([], |row| row.get(1))?.collect();
2028
2029 assert_eq!(results?.concat(), "hello, world!");
2030 Ok(())
2031 }
2032
2033 #[test]
2034 fn test_query_and_then_fails() -> Result<()> {
2035 let db = Connection::open_in_memory()?;
2036 let sql = "BEGIN;
2037 CREATE TABLE foo(x INTEGER, y TEXT);
2038 INSERT INTO foo VALUES(4, \"hello\");
2039 INSERT INTO foo VALUES(3, \", \");
2040 INSERT INTO foo VALUES(2, \"world\");
2041 INSERT INTO foo VALUES(1, \"!\");
2042 END;";
2043 db.execute_batch(sql)?;
2044
2045 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
2046 let bad_type: Result<Vec<f64>> = query.query_and_then([], |row| row.get(1))?.collect();
2047
2048 match bad_type.unwrap_err() {
2049 Error::InvalidColumnType(..) => (),
2050 err => panic!("Unexpected error {err}"),
2051 }
2052
2053 let bad_idx: Result<Vec<String>> =
2054 query.query_and_then([], |row| row.get(3))?.collect();
2055
2056 match bad_idx.unwrap_err() {
2057 Error::InvalidColumnIndex(_) => (),
2058 err => panic!("Unexpected error {err}"),
2059 }
2060 Ok(())
2061 }
2062
2063 #[test]
2064 fn test_query_and_then_custom_error() -> CustomResult<()> {
2065 let db = Connection::open_in_memory()?;
2066 let sql = "BEGIN;
2067 CREATE TABLE foo(x INTEGER, y TEXT);
2068 INSERT INTO foo VALUES(4, \"hello\");
2069 INSERT INTO foo VALUES(3, \", \");
2070 INSERT INTO foo VALUES(2, \"world\");
2071 INSERT INTO foo VALUES(1, \"!\");
2072 END;";
2073 db.execute_batch(sql)?;
2074
2075 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
2076 let results: CustomResult<Vec<String>> = query
2077 .query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite))?
2078 .collect();
2079
2080 assert_eq!(results?.concat(), "hello, world!");
2081 Ok(())
2082 }
2083
2084 #[test]
2085 fn test_query_and_then_custom_error_fails() -> Result<()> {
2086 let db = Connection::open_in_memory()?;
2087 let sql = "BEGIN;
2088 CREATE TABLE foo(x INTEGER, y TEXT);
2089 INSERT INTO foo VALUES(4, \"hello\");
2090 INSERT INTO foo VALUES(3, \", \");
2091 INSERT INTO foo VALUES(2, \"world\");
2092 INSERT INTO foo VALUES(1, \"!\");
2093 END;";
2094 db.execute_batch(sql)?;
2095
2096 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
2097 let bad_type: CustomResult<Vec<f64>> = query
2098 .query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite))?
2099 .collect();
2100
2101 match bad_type.unwrap_err() {
2102 CustomError::Sqlite(Error::InvalidColumnType(..)) => (),
2103 err => panic!("Unexpected error {err}"),
2104 }
2105
2106 let bad_idx: CustomResult<Vec<String>> = query
2107 .query_and_then([], |row| row.get(3).map_err(CustomError::Sqlite))?
2108 .collect();
2109
2110 match bad_idx.unwrap_err() {
2111 CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
2112 err => panic!("Unexpected error {err}"),
2113 }
2114
2115 let non_sqlite_err: CustomResult<Vec<String>> = query
2116 .query_and_then([], |_| Err(CustomError::SomeError))?
2117 .collect();
2118
2119 match non_sqlite_err.unwrap_err() {
2120 CustomError::SomeError => (),
2121 err => panic!("Unexpected error {err}"),
2122 }
2123 Ok(())
2124 }
2125
2126 #[test]
2127 fn test_query_row_and_then_custom_error() -> CustomResult<()> {
2128 let db = Connection::open_in_memory()?;
2129 let sql = "BEGIN;
2130 CREATE TABLE foo(x INTEGER, y TEXT);
2131 INSERT INTO foo VALUES(4, \"hello\");
2132 END;";
2133 db.execute_batch(sql)?;
2134
2135 let query = "SELECT x, y FROM foo ORDER BY x DESC";
2136 let results: CustomResult<String> =
2137 db.query_row_and_then(query, [], |row| row.get(1).map_err(CustomError::Sqlite));
2138
2139 assert_eq!(results?, "hello");
2140 Ok(())
2141 }
2142
2143 #[test]
2144 fn test_query_row_and_then_custom_error_fails() -> Result<()> {
2145 let db = Connection::open_in_memory()?;
2146 let sql = "BEGIN;
2147 CREATE TABLE foo(x INTEGER, y TEXT);
2148 INSERT INTO foo VALUES(4, \"hello\");
2149 END;";
2150 db.execute_batch(sql)?;
2151
2152 let query = "SELECT x, y FROM foo ORDER BY x DESC";
2153 let bad_type: CustomResult<f64> =
2154 db.query_row_and_then(query, [], |row| row.get(1).map_err(CustomError::Sqlite));
2155
2156 match bad_type.unwrap_err() {
2157 CustomError::Sqlite(Error::InvalidColumnType(..)) => (),
2158 err => panic!("Unexpected error {err}"),
2159 }
2160
2161 let bad_idx: CustomResult<String> =
2162 db.query_row_and_then(query, [], |row| row.get(3).map_err(CustomError::Sqlite));
2163
2164 match bad_idx.unwrap_err() {
2165 CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
2166 err => panic!("Unexpected error {err}"),
2167 }
2168
2169 let non_sqlite_err: CustomResult<String> =
2170 db.query_row_and_then(query, [], |_| Err(CustomError::SomeError));
2171
2172 match non_sqlite_err.unwrap_err() {
2173 CustomError::SomeError => (),
2174 err => panic!("Unexpected error {err}"),
2175 }
2176 Ok(())
2177 }
2178 }
2179
2180 #[test]
2181 fn test_dynamic() -> Result<()> {
2182 let db = Connection::open_in_memory()?;
2183 let sql = "BEGIN;
2184 CREATE TABLE foo(x INTEGER, y TEXT);
2185 INSERT INTO foo VALUES(4, \"hello\");
2186 END;";
2187 db.execute_batch(sql)?;
2188
2189 db.query_row("SELECT * FROM foo", [], |r| {
2190 assert_eq!(2, r.as_ref().column_count());
2191 Ok(())
2192 })
2193 }
2194 #[test]
2195 fn test_dyn_box() -> Result<()> {
2196 let db = Connection::open_in_memory()?;
2197 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
2198 let b: Box<dyn ToSql> = Box::new(5);
2199 db.execute("INSERT INTO foo VALUES(?1)", [b])?;
2200 db.query_row("SELECT x FROM foo", [], |r| {
2201 assert_eq!(5, r.get_unwrap::<_, i32>(0));
2202 Ok(())
2203 })
2204 }
2205
2206 #[test]
2207 fn test_params() -> Result<()> {
2208 let db = Connection::open_in_memory()?;
2209 db.query_row(
2210 "SELECT
2211 ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10,
2212 ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19, ?20,
2213 ?21, ?22, ?23, ?24, ?25, ?26, ?27, ?28, ?29, ?30,
2214 ?31, ?32, ?33, ?34;",
2215 params![
2216 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,
2217 1, 1, 1, 1, 1, 1,
2218 ],
2219 |r| {
2220 assert_eq!(1, r.get_unwrap::<_, i32>(0));
2221 Ok(())
2222 },
2223 )
2224 }
2225
2226 #[test]
2227 fn test_alter_table() -> Result<()> {
2228 let db = Connection::open_in_memory()?;
2229 db.execute_batch("CREATE TABLE x(t);")?;
2230 db.execute("ALTER TABLE x RENAME TO y;", [])?;
2232 Ok(())
2233 }
2234
2235 #[test]
2236 fn test_batch() -> Result<()> {
2237 let db = Connection::open_in_memory()?;
2238 let sql = r"
2239 CREATE TABLE tbl1 (col);
2240 CREATE TABLE tbl2 (col);
2241 ";
2242 let mut batch = Batch::new(&db, sql);
2243 while let Some(mut stmt) = batch.next()? {
2244 stmt.execute([])?;
2245 }
2246 Ok(())
2247 }
2248
2249 #[test]
2250 fn test_invalid_batch() -> Result<()> {
2251 let db = Connection::open_in_memory()?;
2252 let sql = r"
2253 PRAGMA test1;
2254 PRAGMA test2=?;
2255 PRAGMA test3;
2256 ";
2257 let mut batch = Batch::new(&db, sql);
2258 assert!(batch.next().is_ok());
2259 assert!(batch.next().is_err());
2260 assert!(batch.next().is_err());
2261 assert!(Batch::new(&db, sql).count().is_err());
2262 Ok(())
2263 }
2264
2265 #[test]
2266 #[cfg(feature = "modern_sqlite")]
2267 fn test_returning() -> Result<()> {
2268 let db = Connection::open_in_memory()?;
2269 db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)")?;
2270 let row_id =
2271 db.one_column::<i64, _>("INSERT INTO foo DEFAULT VALUES RETURNING ROWID", [])?;
2272 assert_eq!(row_id, 1);
2273 Ok(())
2274 }
2275
2276 #[test]
2277 fn test_cache_flush() -> Result<()> {
2278 let db = Connection::open_in_memory()?;
2279 db.cache_flush()
2280 }
2281
2282 #[test]
2283 fn db_readonly() -> Result<()> {
2284 let db = Connection::open_in_memory()?;
2285 assert!(!db.is_readonly(MAIN_DB)?);
2286 Ok(())
2287 }
2288
2289 #[test]
2290 #[cfg(feature = "rusqlite-macros")]
2291 fn prepare_and_bind() -> Result<()> {
2292 let db = Connection::open_in_memory()?;
2293 let name = "Lisa";
2294 let age = 8;
2295 let mut stmt = prepare_and_bind!(db, "SELECT $name, $age;");
2296 let (v1, v2) = stmt
2297 .raw_query()
2298 .next()
2299 .and_then(|o| o.ok_or(Error::QueryReturnedNoRows))
2300 .and_then(|r| Ok((r.get::<_, String>(0)?, r.get::<_, i64>(1)?)))?;
2301 assert_eq!((v1.as_str(), v2), (name, age));
2302 Ok(())
2303 }
2304
2305 #[test]
2306 #[cfg(feature = "modern_sqlite")]
2307 fn test_db_name() -> Result<()> {
2308 let db = Connection::open_in_memory()?;
2309 assert_eq!(db.db_name(0)?, "main");
2310 assert_eq!(db.db_name(1)?, "temp");
2311 assert_eq!(db.db_name(2), Err(Error::InvalidDatabaseIndex(2)));
2312 db.execute_batch("ATTACH DATABASE ':memory:' AS xyz;")?;
2313 assert_eq!(db.db_name(2)?, "xyz");
2314 Ok(())
2315 }
2316
2317 #[test]
2318 #[cfg(feature = "modern_sqlite")]
2319 fn test_is_interrupted() -> Result<()> {
2320 let db = Connection::open_in_memory()?;
2321 assert!(!db.is_interrupted());
2322 db.get_interrupt_handle().interrupt();
2323 assert!(db.is_interrupted());
2324 Ok(())
2325 }
2326
2327 #[test]
2328 fn release_memory() -> Result<()> {
2329 let db = Connection::open_in_memory()?;
2330 db.release_memory()
2331 }
2332}