1#![warn(missing_docs)]
55#![cfg_attr(docsrs, feature(doc_auto_cfg))]
56
57pub use fallible_iterator;
58pub use fallible_streaming_iterator;
59pub use libsqlite3_sys as ffi;
60
61use std::cell::RefCell;
62use std::default::Default;
63use std::ffi::{c_char, c_int, c_uint, CStr, CString};
64use std::fmt;
65
66use std::path::Path;
67use std::result;
68use std::str;
69use std::sync::{Arc, Mutex};
70
71use crate::cache::StatementCache;
72use crate::inner_connection::InnerConnection;
73use crate::raw_statement::RawStatement;
74use crate::types::ValueRef;
75
76pub use crate::bind::BindIndex;
77pub use crate::cache::CachedStatement;
78#[cfg(feature = "column_decltype")]
79pub use crate::column::Column;
80#[cfg(feature = "column_metadata")]
81pub use crate::column::ColumnMetadata;
82pub use crate::error::{to_sqlite_error, Error};
83pub use crate::ffi::ErrorCode;
84#[cfg(feature = "load_extension")]
85pub use crate::load_extension_guard::LoadExtensionGuard;
86pub use crate::params::{params_from_iter, Params, ParamsFromIter};
87pub use crate::row::{AndThenRows, Map, MappedRows, Row, RowIndex, Rows};
88pub use crate::statement::{Statement, StatementStatus};
89#[cfg(feature = "modern_sqlite")]
90pub use crate::transaction::TransactionState;
91pub use crate::transaction::{DropBehavior, Savepoint, Transaction, TransactionBehavior};
92pub use crate::types::ToSql;
93pub use crate::util::Name;
94pub use crate::version::*;
95#[cfg(feature = "rusqlite-macros")]
96#[doc(hidden)]
97pub use rusqlite_macros::__bind;
98
99#[macro_use]
100mod error;
101
102#[cfg(not(feature = "loadable_extension"))]
103pub mod auto_extension;
104#[cfg(feature = "backup")]
105pub mod backup;
106mod bind;
107#[cfg(feature = "blob")]
108pub mod blob;
109mod busy;
110mod cache;
111#[cfg(feature = "collation")]
112mod collation;
113mod column;
114pub mod config;
115#[cfg(any(feature = "functions", feature = "vtab"))]
116mod context;
117#[cfg(feature = "functions")]
118pub mod functions;
119#[cfg(feature = "hooks")]
120pub mod hooks;
121mod inner_connection;
122#[cfg(feature = "limits")]
123pub mod limits;
124#[cfg(feature = "load_extension")]
125mod load_extension_guard;
126mod params;
127mod pragma;
128mod raw_statement;
129mod row;
130#[cfg(feature = "serialize")]
131pub mod serialize;
132#[cfg(feature = "session")]
133pub mod session;
134mod statement;
135#[cfg(feature = "trace")]
136pub mod trace;
137mod transaction;
138pub mod types;
139#[cfg(feature = "unlock_notify")]
140mod unlock_notify;
141mod version;
142#[cfg(feature = "vtab")]
143pub mod vtab;
144
145pub(crate) mod util;
146
147#[cfg(all(feature = "loadable_extension", feature = "load_extension"))]
149compile_error!("feature \"loadable_extension\" and feature \"load_extension\" cannot be enabled at the same time");
150
151const STATEMENT_CACHE_DEFAULT_CAPACITY: usize = 16;
153
154#[macro_export]
177macro_rules! params {
178 () => {
179 &[] as &[&dyn $crate::ToSql]
180 };
181 ($($param:expr),+ $(,)?) => {
182 &[$(&$param as &dyn $crate::ToSql),+] as &[&dyn $crate::ToSql]
183 };
184}
185
186#[macro_export]
214macro_rules! named_params {
215 () => {
216 &[] as &[(&str, &dyn $crate::ToSql)]
217 };
218 ($($param_name:literal: $param_val:expr),+ $(,)?) => {
221 &[$(($param_name, &$param_val as &dyn $crate::ToSql)),+] as &[(&str, &dyn $crate::ToSql)]
222 };
223}
224
225#[cfg(feature = "rusqlite-macros")]
244#[macro_export]
245macro_rules! prepare_and_bind {
246 ($conn:expr, $sql:literal) => {{
247 let mut stmt = $conn.prepare($sql)?;
248 $crate::__bind!(stmt $sql);
249 stmt
250 }};
251}
252
253#[cfg(feature = "rusqlite-macros")]
259#[macro_export]
260macro_rules! prepare_cached_and_bind {
261 ($conn:expr, $sql:literal) => {{
262 let mut stmt = $conn.prepare_cached($sql)?;
263 $crate::__bind!(stmt $sql);
264 stmt
265 }};
266}
267
268pub type Result<T, E = Error> = result::Result<T, E>;
270
271pub trait OptionalExtension<T> {
273 fn optional(self) -> Result<Option<T>>;
279}
280
281impl<T> OptionalExtension<T> for Result<T> {
282 fn optional(self) -> Result<Option<T>> {
283 match self {
284 Ok(value) => Ok(Some(value)),
285 Err(Error::QueryReturnedNoRows) => Ok(None),
286 Err(e) => Err(e),
287 }
288 }
289}
290
291unsafe fn errmsg_to_string(errmsg: *const c_char) -> String {
292 CStr::from_ptr(errmsg).to_string_lossy().into_owned()
293}
294
295#[cfg(any(feature = "functions", feature = "vtab", test))]
296fn str_to_cstring(s: &str) -> Result<util::SmallCString> {
297 Ok(util::SmallCString::new(s)?)
298}
299
300fn str_for_sqlite(s: &[u8]) -> Result<(*const c_char, c_int, ffi::sqlite3_destructor_type)> {
307 let len = len_as_c_int(s.len())?;
308 let (ptr, dtor_info) = if len != 0 {
309 (s.as_ptr().cast::<c_char>(), ffi::SQLITE_TRANSIENT())
310 } else {
311 ("".as_ptr().cast::<c_char>(), ffi::SQLITE_STATIC())
313 };
314 Ok((ptr, len, dtor_info))
315}
316
317fn len_as_c_int(len: usize) -> Result<c_int> {
320 if len >= (c_int::MAX as usize) {
321 Err(err!(ffi::SQLITE_TOOBIG))
322 } else {
323 Ok(len as c_int)
324 }
325}
326
327#[cfg(unix)]
328fn path_to_cstring(p: &Path) -> Result<CString> {
329 use std::os::unix::ffi::OsStrExt;
330 Ok(CString::new(p.as_os_str().as_bytes())?)
331}
332
333#[cfg(not(unix))]
334fn path_to_cstring(p: &Path) -> Result<CString> {
335 let s = p.to_str().ok_or_else(|| Error::InvalidPath(p.to_owned()))?;
336 Ok(CString::new(s)?)
337}
338
339pub const MAIN_DB: &CStr = c"main";
341pub const TEMP_DB: &CStr = c"temp";
343
344pub struct Connection {
346 db: RefCell<InnerConnection>,
347 cache: StatementCache,
348 transaction_behavior: TransactionBehavior,
349}
350
351unsafe impl Send for Connection {}
352
353impl Drop for Connection {
354 #[inline]
355 fn drop(&mut self) {
356 self.flush_prepared_statement_cache();
357 }
358}
359
360impl Connection {
361 #[inline]
414 pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
415 let flags = OpenFlags::default();
416 Self::open_with_flags(path, flags)
417 }
418
419 #[inline]
425 pub fn open_in_memory() -> Result<Self> {
426 let flags = OpenFlags::default();
427 Self::open_in_memory_with_flags(flags)
428 }
429
430 #[inline]
440 pub fn open_with_flags<P: AsRef<Path>>(path: P, flags: OpenFlags) -> Result<Self> {
441 let c_path = path_to_cstring(path.as_ref())?;
442 InnerConnection::open_with_flags(&c_path, flags, None).map(|db| Self {
443 db: RefCell::new(db),
444 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
445 transaction_behavior: TransactionBehavior::Deferred,
446 })
447 }
448
449 #[inline]
460 pub fn open_with_flags_and_vfs<P: AsRef<Path>, V: Name>(
461 path: P,
462 flags: OpenFlags,
463 vfs: V,
464 ) -> Result<Self> {
465 let c_path = path_to_cstring(path.as_ref())?;
466 let c_vfs = vfs.as_cstr()?;
467 InnerConnection::open_with_flags(&c_path, flags, Some(&c_vfs)).map(|db| Self {
468 db: RefCell::new(db),
469 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
470 transaction_behavior: TransactionBehavior::Deferred,
471 })
472 }
473
474 #[inline]
483 pub fn open_in_memory_with_flags(flags: OpenFlags) -> Result<Self> {
484 Self::open_with_flags(":memory:", flags)
485 }
486
487 #[inline]
498 pub fn open_in_memory_with_flags_and_vfs<V: Name>(flags: OpenFlags, vfs: V) -> Result<Self> {
499 Self::open_with_flags_and_vfs(":memory:", flags, vfs)
500 }
501
502 pub fn execute_batch(&self, sql: &str) -> Result<()> {
524 let mut sql = sql;
525 while !sql.is_empty() {
526 let (stmt, tail) = self
527 .db
528 .borrow_mut()
529 .prepare(self, sql, PrepFlags::default())?;
530 if !stmt.stmt.is_null() && stmt.step()? {
531 if false {
533 return Err(Error::ExecuteReturnedResults);
534 }
535 }
536 if tail == 0 || tail >= sql.len() {
537 break;
538 }
539 sql = &sql[tail..];
540 }
541 Ok(())
542 }
543
544 #[inline]
595 pub fn execute<P: Params>(&self, sql: &str, params: P) -> Result<usize> {
596 self.prepare(sql).and_then(|mut stmt| stmt.execute(params))
597 }
598
599 #[inline]
607 pub fn path(&self) -> Option<&str> {
608 unsafe {
609 crate::inner_connection::db_filename(std::marker::PhantomData, self.handle(), MAIN_DB)
610 }
611 }
612
613 #[inline]
618 pub fn release_memory(&self) -> Result<()> {
619 self.db.borrow_mut().release_memory()
620 }
621
622 #[inline]
627 pub fn last_insert_rowid(&self) -> i64 {
628 self.db.borrow_mut().last_insert_rowid()
629 }
630
631 #[inline]
659 pub fn query_row<T, P, F>(&self, sql: &str, params: P, f: F) -> Result<T>
660 where
661 P: Params,
662 F: FnOnce(&Row<'_>) -> Result<T>,
663 {
664 let mut stmt = self.prepare(sql)?;
665 stmt.query_row(params, f)
666 }
667
668 pub fn query_one<T, P, F>(&self, sql: &str, params: P, f: F) -> Result<T>
683 where
684 P: Params,
685 F: FnOnce(&Row<'_>) -> Result<T>,
686 {
687 let mut stmt = self.prepare(sql)?;
688 stmt.query_one(params, f)
689 }
690
691 #[cfg(test)]
693 pub(crate) fn one_column<T, P>(&self, sql: &str, params: P) -> Result<T>
694 where
695 T: types::FromSql,
696 P: Params,
697 {
698 self.query_one(sql, params, |r| r.get(0))
699 }
700
701 #[inline]
727 pub fn query_row_and_then<T, E, P, F>(&self, sql: &str, params: P, f: F) -> Result<T, E>
728 where
729 P: Params,
730 F: FnOnce(&Row<'_>) -> Result<T, E>,
731 E: From<Error>,
732 {
733 let mut stmt = self.prepare(sql)?;
734 let mut rows = stmt.query(params)?;
735
736 rows.get_expected_row().map_err(E::from).and_then(f)
737 }
738
739 #[inline]
758 pub fn prepare(&self, sql: &str) -> Result<Statement<'_>> {
759 self.prepare_with_flags(sql, PrepFlags::default())
760 }
761
762 #[inline]
769 pub fn prepare_with_flags(&self, sql: &str, flags: PrepFlags) -> Result<Statement<'_>> {
770 let (stmt, tail) = self.db.borrow_mut().prepare(self, sql, flags)?;
771 if tail != 0 && !self.prepare(&sql[tail..])?.stmt.is_null() {
772 Err(Error::MultipleStatement)
773 } else {
774 Ok(stmt)
775 }
776 }
777
778 #[allow(clippy::result_large_err)]
788 #[inline]
789 pub fn close(self) -> Result<(), (Self, Error)> {
790 self.flush_prepared_statement_cache();
791 let r = self.db.borrow_mut().close();
792 r.map_err(move |err| (self, err))
793 }
794
795 #[cfg(feature = "load_extension")]
848 #[inline]
849 pub unsafe fn load_extension_enable(&self) -> Result<()> {
850 self.db.borrow_mut().enable_load_extension(1)
851 }
852
853 #[cfg(feature = "load_extension")]
861 #[inline]
862 pub fn load_extension_disable(&self) -> Result<()> {
863 unsafe { self.db.borrow_mut().enable_load_extension(0) }
865 }
866
867 #[cfg(feature = "load_extension")]
903 #[inline]
904 pub unsafe fn load_extension<P: AsRef<Path>, N: Name>(
905 &self,
906 dylib_path: P,
907 entry_point: Option<N>,
908 ) -> Result<()> {
909 self.db
910 .borrow_mut()
911 .load_extension(dylib_path.as_ref(), entry_point)
912 }
913
914 #[inline]
928 pub unsafe fn handle(&self) -> *mut ffi::sqlite3 {
929 self.db.borrow().db()
930 }
931
932 #[inline]
941 pub unsafe fn from_handle(db: *mut ffi::sqlite3) -> Result<Self> {
942 let db = InnerConnection::new(db, false);
943 Ok(Self {
944 db: RefCell::new(db),
945 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
946 transaction_behavior: TransactionBehavior::Deferred,
947 })
948 }
949
950 #[cfg(feature = "loadable_extension")]
956 pub unsafe fn extension_init2(
957 db: *mut ffi::sqlite3,
958 pz_err_msg: *mut *mut c_char,
959 p_api: *mut ffi::sqlite3_api_routines,
960 init: fn(Self) -> Result<bool>,
961 ) -> c_int {
962 if p_api.is_null() {
963 return ffi::SQLITE_ERROR;
964 }
965 match ffi::rusqlite_extension_init2(p_api)
966 .map_err(Error::from)
967 .and(Self::from_handle(db))
968 .and_then(init)
969 {
970 Err(err) => to_sqlite_error(&err, pz_err_msg),
971 Ok(true) => ffi::SQLITE_OK_LOAD_PERMANENTLY,
972 _ => ffi::SQLITE_OK,
973 }
974 }
975
976 #[inline]
989 pub unsafe fn from_handle_owned(db: *mut ffi::sqlite3) -> Result<Self> {
990 let db = InnerConnection::new(db, true);
991 Ok(Self {
992 db: RefCell::new(db),
993 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
994 transaction_behavior: TransactionBehavior::Deferred,
995 })
996 }
997
998 #[inline]
1001 pub fn get_interrupt_handle(&self) -> InterruptHandle {
1002 self.db.borrow().get_interrupt_handle()
1003 }
1004
1005 #[inline]
1006 fn decode_result(&self, code: c_int) -> Result<()> {
1007 self.db.borrow().decode_result(code)
1008 }
1009
1010 #[inline]
1016 pub fn changes(&self) -> u64 {
1017 self.db.borrow().changes()
1018 }
1019
1020 #[inline]
1026 pub fn total_changes(&self) -> u64 {
1027 self.db.borrow().total_changes()
1028 }
1029
1030 #[inline]
1033 pub fn is_autocommit(&self) -> bool {
1034 self.db.borrow().is_autocommit()
1035 }
1036
1037 #[inline]
1039 pub fn is_busy(&self) -> bool {
1040 self.db.borrow().is_busy()
1041 }
1042
1043 pub fn cache_flush(&self) -> Result<()> {
1045 self.db.borrow_mut().cache_flush()
1046 }
1047
1048 pub fn is_readonly<N: Name>(&self, db_name: N) -> Result<bool> {
1050 self.db.borrow().db_readonly(db_name)
1051 }
1052
1053 #[cfg(feature = "modern_sqlite")] pub fn db_name(&self, index: usize) -> Result<String> {
1060 unsafe {
1061 let db = self.handle();
1062 let name = ffi::sqlite3_db_name(db, index as c_int);
1063 if name.is_null() {
1064 Err(Error::InvalidDatabaseIndex(index))
1065 } else {
1066 Ok(CStr::from_ptr(name).to_str()?.to_owned())
1067 }
1068 }
1069 }
1070
1071 #[cfg(feature = "modern_sqlite")] pub fn is_interrupted(&self) -> bool {
1074 self.db.borrow().is_interrupted()
1075 }
1076}
1077
1078impl fmt::Debug for Connection {
1079 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1080 f.debug_struct("Connection")
1081 .field("path", &self.path())
1082 .finish()
1083 }
1084}
1085
1086#[derive(Debug)]
1111pub struct Batch<'conn, 'sql> {
1112 conn: &'conn Connection,
1113 sql: &'sql str,
1114 tail: usize,
1115}
1116
1117impl<'conn, 'sql> Batch<'conn, 'sql> {
1118 pub fn new(conn: &'conn Connection, sql: &'sql str) -> Self {
1120 Batch { conn, sql, tail: 0 }
1121 }
1122}
1123impl<'conn> fallible_iterator::FallibleIterator for Batch<'conn, '_> {
1124 type Error = Error;
1125 type Item = Statement<'conn>;
1126
1127 fn next(&mut self) -> Result<Option<Statement<'conn>>> {
1131 while self.tail < self.sql.len() {
1132 let sql = &self.sql[self.tail..];
1133 let (next, tail) =
1134 self.conn
1135 .db
1136 .borrow_mut()
1137 .prepare(self.conn, sql, PrepFlags::default())?;
1138 if tail == 0 {
1139 self.tail = self.sql.len();
1140 } else {
1141 self.tail += tail;
1142 }
1143 if next.stmt.is_null() {
1144 continue;
1145 }
1146 return Ok(Some(next));
1147 }
1148 Ok(None)
1149 }
1150}
1151
1152bitflags::bitflags! {
1153 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1160 #[repr(C)]
1161 pub struct OpenFlags: c_int {
1162 const SQLITE_OPEN_READ_ONLY = ffi::SQLITE_OPEN_READONLY;
1165 const SQLITE_OPEN_READ_WRITE = ffi::SQLITE_OPEN_READWRITE;
1169 const SQLITE_OPEN_CREATE = ffi::SQLITE_OPEN_CREATE;
1171 const SQLITE_OPEN_URI = ffi::SQLITE_OPEN_URI;
1173 const SQLITE_OPEN_MEMORY = ffi::SQLITE_OPEN_MEMORY;
1175 const SQLITE_OPEN_NO_MUTEX = ffi::SQLITE_OPEN_NOMUTEX;
1184 const SQLITE_OPEN_FULL_MUTEX = ffi::SQLITE_OPEN_FULLMUTEX;
1208 const SQLITE_OPEN_SHARED_CACHE = 0x0002_0000;
1215 const SQLITE_OPEN_PRIVATE_CACHE = 0x0004_0000;
1217 const SQLITE_OPEN_NOFOLLOW = 0x0100_0000;
1219 const SQLITE_OPEN_EXRESCODE = 0x0200_0000;
1221 }
1222}
1223
1224impl Default for OpenFlags {
1225 #[inline]
1226 fn default() -> Self {
1227 Self::SQLITE_OPEN_READ_WRITE
1230 | Self::SQLITE_OPEN_CREATE
1231 | Self::SQLITE_OPEN_NO_MUTEX
1232 | Self::SQLITE_OPEN_URI
1233 }
1234}
1235
1236bitflags::bitflags! {
1237 #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
1240 #[repr(C)]
1241 pub struct PrepFlags: c_uint {
1242 const SQLITE_PREPARE_PERSISTENT = 0x01;
1244 const SQLITE_PREPARE_NO_VTAB = 0x04;
1246 const SQLITE_PREPARE_DONT_LOG = 0x10;
1248 }
1249}
1250
1251pub struct InterruptHandle {
1253 db_lock: Arc<Mutex<*mut ffi::sqlite3>>,
1254}
1255
1256unsafe impl Send for InterruptHandle {}
1257unsafe impl Sync for InterruptHandle {}
1258
1259impl InterruptHandle {
1260 pub fn interrupt(&self) {
1263 let db_handle = self.db_lock.lock().unwrap();
1264 if !db_handle.is_null() {
1265 unsafe { ffi::sqlite3_interrupt(*db_handle) }
1266 }
1267 }
1268}
1269
1270#[cfg(doctest)]
1271doc_comment::doctest!("../README.md");
1272
1273#[cfg(test)]
1274mod test {
1275 use super::*;
1276 use fallible_iterator::FallibleIterator;
1277 use std::error::Error as StdError;
1278 use std::fmt;
1279
1280 #[allow(dead_code)]
1284 #[expect(unconditional_recursion, clippy::extra_unused_type_parameters)]
1285 fn ensure_send<T: Send>() {
1286 ensure_send::<Connection>();
1287 ensure_send::<InterruptHandle>();
1288 }
1289
1290 #[allow(dead_code)]
1291 #[expect(unconditional_recursion, clippy::extra_unused_type_parameters)]
1292 fn ensure_sync<T: Sync>() {
1293 ensure_sync::<InterruptHandle>();
1294 }
1295
1296 fn checked_memory_handle() -> Connection {
1297 Connection::open_in_memory().unwrap()
1298 }
1299
1300 #[test]
1301 fn test_concurrent_transactions_busy_commit() -> Result<()> {
1302 use std::time::Duration;
1303 let tmp = tempfile::tempdir().unwrap();
1304 let path = tmp.path().join("transactions.db3");
1305
1306 Connection::open(&path)?.execute_batch(
1307 "
1308 BEGIN; CREATE TABLE foo(x INTEGER);
1309 INSERT INTO foo VALUES(42); END;",
1310 )?;
1311
1312 let mut db1 = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_WRITE)?;
1313 let mut db2 = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_ONLY)?;
1314
1315 db1.busy_timeout(Duration::from_millis(0))?;
1316 db2.busy_timeout(Duration::from_millis(0))?;
1317
1318 {
1319 let tx1 = db1.transaction()?;
1320 let tx2 = db2.transaction()?;
1321
1322 tx1.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))?;
1324 tx2.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))?;
1325
1326 tx1.execute("INSERT INTO foo VALUES(?1)", [1])?;
1327 let _ = tx2.execute("INSERT INTO foo VALUES(?1)", [2]);
1328
1329 let _ = tx1.commit();
1330 let _ = tx2.commit();
1331 }
1332
1333 let _ = db1
1334 .transaction()
1335 .expect("commit should have closed transaction");
1336 let _ = db2
1337 .transaction()
1338 .expect("commit should have closed transaction");
1339 Ok(())
1340 }
1341
1342 #[test]
1343 fn test_persistence() -> Result<()> {
1344 let temp_dir = tempfile::tempdir().unwrap();
1345 let path = temp_dir.path().join("test.db3");
1346
1347 {
1348 let db = Connection::open(&path)?;
1349 let sql = "BEGIN;
1350 CREATE TABLE foo(x INTEGER);
1351 INSERT INTO foo VALUES(42);
1352 END;";
1353 db.execute_batch(sql)?;
1354 }
1355
1356 let path_string = path.to_str().unwrap();
1357 let db = Connection::open(path_string)?;
1358
1359 assert_eq!(42, db.one_column::<i64, _>("SELECT x FROM foo", [])?);
1360 Ok(())
1361 }
1362
1363 #[test]
1364 fn test_open() {
1365 Connection::open_in_memory().unwrap();
1366
1367 let db = checked_memory_handle();
1368 db.close().unwrap();
1369 }
1370
1371 #[test]
1372 fn test_path() -> Result<()> {
1373 let tmp = tempfile::tempdir().unwrap();
1374 let db = Connection::open("")?;
1375 assert_eq!(Some(""), db.path());
1376 let db = Connection::open_in_memory()?;
1377 assert_eq!(Some(""), db.path());
1378 let db = Connection::open("file:dummy.db?mode=memory&cache=shared")?;
1379 assert_eq!(Some(""), db.path());
1380 let path = tmp.path().join("file.db");
1381 let db = Connection::open(path)?;
1382 assert!(db.path().is_some_and(|p| p.ends_with("file.db")));
1383 Ok(())
1384 }
1385
1386 #[test]
1387 fn test_open_failure() {
1388 let filename = "no_such_file.db";
1389 let result = Connection::open_with_flags(filename, OpenFlags::SQLITE_OPEN_READ_ONLY);
1390 let err = result.unwrap_err();
1391 if let Error::SqliteFailure(e, Some(msg)) = err {
1392 assert_eq!(ErrorCode::CannotOpen, e.code);
1393 assert_eq!(ffi::SQLITE_CANTOPEN, e.extended_code);
1394 assert!(
1395 msg.contains(filename),
1396 "error message '{msg}' does not contain '{filename}'"
1397 );
1398 } else {
1399 panic!("SqliteFailure expected");
1400 }
1401 }
1402
1403 #[cfg(unix)]
1404 #[test]
1405 fn test_invalid_unicode_file_names() -> Result<()> {
1406 use std::ffi::OsStr;
1407 use std::fs::File;
1408 use std::os::unix::ffi::OsStrExt;
1409 let temp_dir = tempfile::tempdir().unwrap();
1410
1411 let path = temp_dir.path();
1412 if File::create(path.join(OsStr::from_bytes(&[0xFE]))).is_err() {
1413 return Ok(());
1415 }
1416 let db_path = path.join(OsStr::from_bytes(&[0xFF]));
1417 {
1418 let db = Connection::open(&db_path)?;
1419 let sql = "BEGIN;
1420 CREATE TABLE foo(x INTEGER);
1421 INSERT INTO foo VALUES(42);
1422 END;";
1423 db.execute_batch(sql)?;
1424 }
1425
1426 let db = Connection::open(&db_path)?;
1427
1428 assert_eq!(42, db.one_column::<i64, _>("SELECT x FROM foo", [])?);
1429 Ok(())
1430 }
1431
1432 #[test]
1433 fn test_close_retry() -> Result<()> {
1434 let db = Connection::open_in_memory()?;
1435
1436 let raw_stmt = {
1440 use super::str_to_cstring;
1441 use std::ffi::c_int;
1442 use std::ptr;
1443
1444 let raw_db = db.db.borrow_mut().db;
1445 let sql = "SELECT 1";
1446 let mut raw_stmt: *mut ffi::sqlite3_stmt = ptr::null_mut();
1447 let cstring = str_to_cstring(sql)?;
1448 let rc = unsafe {
1449 ffi::sqlite3_prepare_v2(
1450 raw_db,
1451 cstring.as_ptr(),
1452 (sql.len() + 1) as c_int,
1453 &mut raw_stmt,
1454 ptr::null_mut(),
1455 )
1456 };
1457 assert_eq!(rc, ffi::SQLITE_OK);
1458 raw_stmt
1459 };
1460
1461 let (db, _) = db.close().unwrap_err();
1464 let (db, _) = db.close().unwrap_err();
1465 let (db, _) = db.close().unwrap_err();
1466
1467 assert_eq!(ffi::SQLITE_OK, unsafe { ffi::sqlite3_finalize(raw_stmt) });
1469
1470 db.close().unwrap();
1471 Ok(())
1472 }
1473
1474 #[test]
1475 fn test_open_with_flags() {
1476 for bad_flags in &[
1477 OpenFlags::empty(),
1478 OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_READ_WRITE,
1479 OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_CREATE,
1480 ] {
1481 Connection::open_in_memory_with_flags(*bad_flags).unwrap_err();
1482 }
1483 }
1484
1485 #[test]
1486 fn test_execute_batch() -> Result<()> {
1487 let db = Connection::open_in_memory()?;
1488 let sql = "BEGIN;
1489 CREATE TABLE foo(x INTEGER);
1490 INSERT INTO foo VALUES(1);
1491 INSERT INTO foo VALUES(2);
1492 INSERT INTO foo VALUES(3);
1493 INSERT INTO foo VALUES(4);
1494 END;";
1495 db.execute_batch(sql)?;
1496
1497 db.execute_batch("UPDATE foo SET x = 3 WHERE x < 3")?;
1498
1499 db.execute_batch("INVALID SQL").unwrap_err();
1500
1501 db.execute_batch("PRAGMA locking_mode = EXCLUSIVE")?;
1502 Ok(())
1503 }
1504
1505 #[test]
1506 fn test_execute() -> Result<()> {
1507 let db = Connection::open_in_memory()?;
1508 db.execute_batch("CREATE TABLE foo(x INTEGER)")?;
1509
1510 assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?1)", [1i32])?);
1511 assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?1)", [2i32])?);
1512
1513 assert_eq!(3, db.one_column::<i32, _>("SELECT SUM(x) FROM foo", [])?);
1514 Ok(())
1515 }
1516
1517 #[test]
1518 #[cfg(feature = "extra_check")]
1519 fn test_execute_select_with_no_row() {
1520 let db = checked_memory_handle();
1521 let err = db.execute("SELECT 1 WHERE 1 < ?1", [1i32]).unwrap_err();
1522 assert_eq!(
1523 err,
1524 Error::ExecuteReturnedResults,
1525 "Unexpected error: {err}"
1526 );
1527 }
1528
1529 #[test]
1530 fn test_execute_select_with_row() {
1531 let db = checked_memory_handle();
1532 let err = db.execute("SELECT 1", []).unwrap_err();
1533 assert_eq!(err, Error::ExecuteReturnedResults);
1534 }
1535
1536 #[test]
1537 fn test_execute_multiple() {
1538 let db = checked_memory_handle();
1539 let err = db
1540 .execute(
1541 "CREATE TABLE foo(x INTEGER); CREATE TABLE foo(x INTEGER)",
1542 [],
1543 )
1544 .unwrap_err();
1545 match err {
1546 Error::MultipleStatement => (),
1547 _ => panic!("Unexpected error: {err}"),
1548 }
1549 db.execute("CREATE TABLE t(c); -- bim", [])
1550 .expect("Tail comment should be ignored");
1551 }
1552
1553 #[test]
1554 fn test_prepare_column_names() -> Result<()> {
1555 let db = Connection::open_in_memory()?;
1556 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1557
1558 let stmt = db.prepare("SELECT * FROM foo")?;
1559 assert_eq!(stmt.column_count(), 1);
1560 assert_eq!(stmt.column_names(), vec!["x"]);
1561
1562 let stmt = db.prepare("SELECT x AS a, x AS b FROM foo")?;
1563 assert_eq!(stmt.column_count(), 2);
1564 assert_eq!(stmt.column_names(), vec!["a", "b"]);
1565 Ok(())
1566 }
1567
1568 #[test]
1569 fn test_prepare_execute() -> Result<()> {
1570 let db = Connection::open_in_memory()?;
1571 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1572
1573 let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?1)")?;
1574 assert_eq!(insert_stmt.execute([1i32])?, 1);
1575 assert_eq!(insert_stmt.execute([2i32])?, 1);
1576 assert_eq!(insert_stmt.execute([3i32])?, 1);
1577
1578 assert_eq!(insert_stmt.execute(["hello"])?, 1);
1579 assert_eq!(insert_stmt.execute(["goodbye"])?, 1);
1580 assert_eq!(insert_stmt.execute([types::Null])?, 1);
1581
1582 let mut update_stmt = db.prepare("UPDATE foo SET x=?1 WHERE x<?2")?;
1583 assert_eq!(update_stmt.execute([3i32, 3i32])?, 2);
1584 assert_eq!(update_stmt.execute([3i32, 3i32])?, 0);
1585 assert_eq!(update_stmt.execute([8i32, 8i32])?, 3);
1586 Ok(())
1587 }
1588
1589 #[test]
1590 fn test_prepare_query() -> Result<()> {
1591 let db = Connection::open_in_memory()?;
1592 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1593
1594 let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?1)")?;
1595 assert_eq!(insert_stmt.execute([1i32])?, 1);
1596 assert_eq!(insert_stmt.execute([2i32])?, 1);
1597 assert_eq!(insert_stmt.execute([3i32])?, 1);
1598
1599 let mut query = db.prepare("SELECT x FROM foo WHERE x < ?1 ORDER BY x DESC")?;
1600 {
1601 let mut rows = query.query([4i32])?;
1602 let mut v = Vec::<i32>::new();
1603
1604 while let Some(row) = rows.next()? {
1605 v.push(row.get(0)?);
1606 }
1607
1608 assert_eq!(v, [3i32, 2, 1]);
1609 }
1610
1611 {
1612 let mut rows = query.query([3i32])?;
1613 let mut v = Vec::<i32>::new();
1614
1615 while let Some(row) = rows.next()? {
1616 v.push(row.get(0)?);
1617 }
1618
1619 assert_eq!(v, [2i32, 1]);
1620 }
1621 Ok(())
1622 }
1623
1624 #[test]
1625 fn test_query_map() -> Result<()> {
1626 let db = Connection::open_in_memory()?;
1627 let sql = "BEGIN;
1628 CREATE TABLE foo(x INTEGER, y TEXT);
1629 INSERT INTO foo VALUES(4, \"hello\");
1630 INSERT INTO foo VALUES(3, \", \");
1631 INSERT INTO foo VALUES(2, \"world\");
1632 INSERT INTO foo VALUES(1, \"!\");
1633 END;";
1634 db.execute_batch(sql)?;
1635
1636 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1637 let results: Result<Vec<String>> = query.query([])?.map(|row| row.get(1)).collect();
1638
1639 assert_eq!(results?.concat(), "hello, world!");
1640 Ok(())
1641 }
1642
1643 #[test]
1644 fn test_query_row() -> Result<()> {
1645 let db = Connection::open_in_memory()?;
1646 let sql = "BEGIN;
1647 CREATE TABLE foo(x INTEGER);
1648 INSERT INTO foo VALUES(1);
1649 INSERT INTO foo VALUES(2);
1650 INSERT INTO foo VALUES(3);
1651 INSERT INTO foo VALUES(4);
1652 END;";
1653 db.execute_batch(sql)?;
1654
1655 assert_eq!(10, db.one_column::<i64, _>("SELECT SUM(x) FROM foo", [])?);
1656
1657 let result: Result<i64> = db.one_column("SELECT x FROM foo WHERE x > 5", []);
1658 match result.unwrap_err() {
1659 Error::QueryReturnedNoRows => (),
1660 err => panic!("Unexpected error {err}"),
1661 }
1662
1663 db.query_row("NOT A PROPER QUERY; test123", [], |_| Ok(()))
1664 .unwrap_err();
1665
1666 db.query_row("SELECT 1; SELECT 2;", [], |_| Ok(()))
1667 .unwrap_err();
1668
1669 Ok(())
1670 }
1671
1672 #[test]
1673 fn test_optional() -> Result<()> {
1674 let db = Connection::open_in_memory()?;
1675
1676 let result: Result<i64> = db.one_column("SELECT 1 WHERE 0 <> 0", []);
1677 let result = result.optional();
1678 match result? {
1679 None => (),
1680 _ => panic!("Unexpected result"),
1681 }
1682
1683 let result: Result<i64> = db.one_column("SELECT 1 WHERE 0 == 0", []);
1684 let result = result.optional();
1685 match result? {
1686 Some(1) => (),
1687 _ => panic!("Unexpected result"),
1688 }
1689
1690 let bad_query_result: Result<i64> = db.one_column("NOT A PROPER QUERY", []);
1691 let bad_query_result = bad_query_result.optional();
1692 bad_query_result.unwrap_err();
1693 Ok(())
1694 }
1695
1696 #[test]
1697 fn test_pragma_query_row() -> Result<()> {
1698 let db = Connection::open_in_memory()?;
1699 assert_eq!(
1700 "memory",
1701 db.one_column::<String, _>("PRAGMA journal_mode", [])?
1702 );
1703 let mode = db.one_column::<String, _>("PRAGMA journal_mode=off", [])?;
1704 if cfg!(feature = "bundled") {
1705 assert_eq!(mode, "off");
1706 } else {
1707 assert!(mode == "memory" || mode == "off", "Got mode {mode:?}");
1719 }
1720
1721 Ok(())
1722 }
1723
1724 #[test]
1725 fn test_prepare_failures() -> Result<()> {
1726 let db = Connection::open_in_memory()?;
1727 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1728
1729 let err = db.prepare("SELECT * FROM does_not_exist").unwrap_err();
1730 assert!(format!("{err}").contains("does_not_exist"));
1731 Ok(())
1732 }
1733
1734 #[test]
1735 fn test_last_insert_rowid() -> Result<()> {
1736 let db = Connection::open_in_memory()?;
1737 db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)")?;
1738 db.execute_batch("INSERT INTO foo DEFAULT VALUES")?;
1739
1740 assert_eq!(db.last_insert_rowid(), 1);
1741
1742 let mut stmt = db.prepare("INSERT INTO foo DEFAULT VALUES")?;
1743 for _ in 0i32..9 {
1744 stmt.execute([])?;
1745 }
1746 assert_eq!(db.last_insert_rowid(), 10);
1747 Ok(())
1748 }
1749
1750 #[test]
1751 fn test_total_changes() -> Result<()> {
1752 let db = Connection::open_in_memory()?;
1753 let sql = "CREATE TABLE foo(x INTEGER PRIMARY KEY, value TEXT default '' NOT NULL,
1754 desc TEXT default '');
1755 CREATE VIEW foo_bar AS SELECT x, desc FROM foo WHERE value = 'bar';
1756 CREATE TRIGGER INSERT_FOOBAR
1757 INSTEAD OF INSERT
1758 ON foo_bar
1759 BEGIN
1760 INSERT INTO foo VALUES(new.x, 'bar', new.desc);
1761 END;";
1762 db.execute_batch(sql)?;
1763 let total_changes_before = db.total_changes();
1764 let changes = db
1765 .prepare("INSERT INTO foo_bar VALUES(null, 'baz');")?
1766 .execute([])?;
1767 let total_changes_after = db.total_changes();
1768 assert_eq!(changes, 0);
1769 assert_eq!(total_changes_after - total_changes_before, 1);
1770 Ok(())
1771 }
1772
1773 #[test]
1774 fn test_is_autocommit() -> Result<()> {
1775 let db = Connection::open_in_memory()?;
1776 assert!(
1777 db.is_autocommit(),
1778 "autocommit expected to be active by default"
1779 );
1780 Ok(())
1781 }
1782
1783 #[test]
1784 fn test_is_busy() -> Result<()> {
1785 let db = Connection::open_in_memory()?;
1786 assert!(!db.is_busy());
1787 let mut stmt = db.prepare("PRAGMA schema_version")?;
1788 assert!(!db.is_busy());
1789 {
1790 let mut rows = stmt.query([])?;
1791 assert!(!db.is_busy());
1792 let row = rows.next()?;
1793 assert!(db.is_busy());
1794 assert!(row.is_some());
1795 }
1796 assert!(!db.is_busy());
1797 Ok(())
1798 }
1799
1800 #[test]
1801 fn test_statement_debugging() -> Result<()> {
1802 let db = Connection::open_in_memory()?;
1803 let query = "SELECT 12345";
1804 let stmt = db.prepare(query)?;
1805
1806 assert!(format!("{stmt:?}").contains(query));
1807 Ok(())
1808 }
1809
1810 #[test]
1811 fn test_notnull_constraint_error() -> Result<()> {
1812 let db = Connection::open_in_memory()?;
1813 db.execute_batch("CREATE TABLE foo(x NOT NULL)")?;
1814
1815 let result = db.execute("INSERT INTO foo (x) VALUES (NULL)", []);
1816
1817 match result.unwrap_err() {
1818 Error::SqliteFailure(err, _) => {
1819 assert_eq!(err.code, ErrorCode::ConstraintViolation);
1820 assert_eq!(err.extended_code, ffi::SQLITE_CONSTRAINT_NOTNULL);
1821 }
1822 err => panic!("Unexpected error {err}"),
1823 }
1824 Ok(())
1825 }
1826
1827 #[test]
1828 fn test_version_string() {
1829 let n = version_number();
1830 let major = n / 1_000_000;
1831 let minor = (n % 1_000_000) / 1_000;
1832 let patch = n % 1_000;
1833
1834 assert!(version().contains(&format!("{major}.{minor}.{patch}")));
1835 }
1836
1837 #[test]
1838 #[cfg(feature = "functions")]
1839 fn test_interrupt() -> Result<()> {
1840 let db = Connection::open_in_memory()?;
1841
1842 let interrupt_handle = db.get_interrupt_handle();
1843
1844 db.create_scalar_function(
1845 "interrupt",
1846 0,
1847 functions::FunctionFlags::default(),
1848 move |_| {
1849 interrupt_handle.interrupt();
1850 Ok(0)
1851 },
1852 )?;
1853
1854 let mut stmt =
1855 db.prepare("SELECT interrupt() FROM (SELECT 1 UNION SELECT 2 UNION SELECT 3)")?;
1856
1857 let result: Result<Vec<i32>> = stmt.query([])?.map(|r| r.get(0)).collect();
1858
1859 assert_eq!(
1860 result.unwrap_err().sqlite_error_code(),
1861 Some(ErrorCode::OperationInterrupted)
1862 );
1863 Ok(())
1864 }
1865
1866 #[test]
1867 fn test_interrupt_close() {
1868 let db = checked_memory_handle();
1869 let handle = db.get_interrupt_handle();
1870 handle.interrupt();
1871 db.close().unwrap();
1872 handle.interrupt();
1873
1874 let db_guard = handle.db_lock.lock().unwrap();
1876 assert!(db_guard.is_null());
1877 }
1881
1882 #[test]
1883 fn test_get_raw() -> Result<()> {
1884 let db = Connection::open_in_memory()?;
1885 db.execute_batch("CREATE TABLE foo(i, x);")?;
1886 let vals = ["foobar", "1234", "qwerty"];
1887 let mut insert_stmt = db.prepare("INSERT INTO foo(i, x) VALUES(?1, ?2)")?;
1888 for (i, v) in vals.iter().enumerate() {
1889 let i_to_insert = i as i64;
1890 assert_eq!(insert_stmt.execute(params![i_to_insert, v])?, 1);
1891 }
1892
1893 let mut query = db.prepare("SELECT i, x FROM foo")?;
1894 let mut rows = query.query([])?;
1895
1896 while let Some(row) = rows.next()? {
1897 let i = row.get_ref(0)?.as_i64()?;
1898 let expect = vals[i as usize];
1899 let x = row.get_ref("x")?.as_str()?;
1900 assert_eq!(x, expect);
1901 }
1902
1903 let mut query = db.prepare("SELECT x FROM foo")?;
1904 let rows = query.query_map([], |row| {
1905 let x = row.get_ref(0)?.as_str()?; Ok(x[..].to_owned())
1907 })?;
1908
1909 for (i, row) in rows.enumerate() {
1910 assert_eq!(row?, vals[i]);
1911 }
1912 Ok(())
1913 }
1914
1915 #[test]
1916 fn test_from_handle() -> Result<()> {
1917 let db = Connection::open_in_memory()?;
1918 let handle = unsafe { db.handle() };
1919 {
1920 let db = unsafe { Connection::from_handle(handle) }?;
1921 db.execute_batch("PRAGMA VACUUM")?;
1922 }
1923 db.close().unwrap();
1924 Ok(())
1925 }
1926
1927 #[test]
1928 fn test_from_handle_owned() -> Result<()> {
1929 let mut handle: *mut ffi::sqlite3 = std::ptr::null_mut();
1930 let r = unsafe { ffi::sqlite3_open(c":memory:".as_ptr(), &mut handle) };
1931 assert_eq!(r, ffi::SQLITE_OK);
1932 let db = unsafe { Connection::from_handle_owned(handle) }?;
1933 db.execute_batch("PRAGMA VACUUM")?;
1934 Ok(())
1935 }
1936
1937 mod query_and_then_tests {
1938
1939 use super::*;
1940
1941 #[derive(Debug)]
1942 enum CustomError {
1943 SomeError,
1944 Sqlite(Error),
1945 }
1946
1947 impl fmt::Display for CustomError {
1948 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1949 match *self {
1950 Self::SomeError => write!(f, "my custom error"),
1951 Self::Sqlite(ref se) => write!(f, "my custom error: {se}"),
1952 }
1953 }
1954 }
1955
1956 impl StdError for CustomError {
1957 fn description(&self) -> &str {
1958 "my custom error"
1959 }
1960
1961 fn cause(&self) -> Option<&dyn StdError> {
1962 match *self {
1963 Self::SomeError => None,
1964 Self::Sqlite(ref se) => Some(se),
1965 }
1966 }
1967 }
1968
1969 impl From<Error> for CustomError {
1970 fn from(se: Error) -> Self {
1971 Self::Sqlite(se)
1972 }
1973 }
1974
1975 type CustomResult<T> = Result<T, CustomError>;
1976
1977 #[test]
1978 fn test_query_and_then() -> Result<()> {
1979 let db = Connection::open_in_memory()?;
1980 let sql = "BEGIN;
1981 CREATE TABLE foo(x INTEGER, y TEXT);
1982 INSERT INTO foo VALUES(4, \"hello\");
1983 INSERT INTO foo VALUES(3, \", \");
1984 INSERT INTO foo VALUES(2, \"world\");
1985 INSERT INTO foo VALUES(1, \"!\");
1986 END;";
1987 db.execute_batch(sql)?;
1988
1989 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1990 let results: Result<Vec<String>> =
1991 query.query_and_then([], |row| row.get(1))?.collect();
1992
1993 assert_eq!(results?.concat(), "hello, world!");
1994 Ok(())
1995 }
1996
1997 #[test]
1998 fn test_query_and_then_fails() -> Result<()> {
1999 let db = Connection::open_in_memory()?;
2000 let sql = "BEGIN;
2001 CREATE TABLE foo(x INTEGER, y TEXT);
2002 INSERT INTO foo VALUES(4, \"hello\");
2003 INSERT INTO foo VALUES(3, \", \");
2004 INSERT INTO foo VALUES(2, \"world\");
2005 INSERT INTO foo VALUES(1, \"!\");
2006 END;";
2007 db.execute_batch(sql)?;
2008
2009 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
2010 let bad_type: Result<Vec<f64>> = query.query_and_then([], |row| row.get(1))?.collect();
2011
2012 match bad_type.unwrap_err() {
2013 Error::InvalidColumnType(..) => (),
2014 err => panic!("Unexpected error {err}"),
2015 }
2016
2017 let bad_idx: Result<Vec<String>> =
2018 query.query_and_then([], |row| row.get(3))?.collect();
2019
2020 match bad_idx.unwrap_err() {
2021 Error::InvalidColumnIndex(_) => (),
2022 err => panic!("Unexpected error {err}"),
2023 }
2024 Ok(())
2025 }
2026
2027 #[test]
2028 fn test_query_and_then_custom_error() -> CustomResult<()> {
2029 let db = Connection::open_in_memory()?;
2030 let sql = "BEGIN;
2031 CREATE TABLE foo(x INTEGER, y TEXT);
2032 INSERT INTO foo VALUES(4, \"hello\");
2033 INSERT INTO foo VALUES(3, \", \");
2034 INSERT INTO foo VALUES(2, \"world\");
2035 INSERT INTO foo VALUES(1, \"!\");
2036 END;";
2037 db.execute_batch(sql)?;
2038
2039 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
2040 let results: CustomResult<Vec<String>> = query
2041 .query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite))?
2042 .collect();
2043
2044 assert_eq!(results?.concat(), "hello, world!");
2045 Ok(())
2046 }
2047
2048 #[test]
2049 fn test_query_and_then_custom_error_fails() -> Result<()> {
2050 let db = Connection::open_in_memory()?;
2051 let sql = "BEGIN;
2052 CREATE TABLE foo(x INTEGER, y TEXT);
2053 INSERT INTO foo VALUES(4, \"hello\");
2054 INSERT INTO foo VALUES(3, \", \");
2055 INSERT INTO foo VALUES(2, \"world\");
2056 INSERT INTO foo VALUES(1, \"!\");
2057 END;";
2058 db.execute_batch(sql)?;
2059
2060 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
2061 let bad_type: CustomResult<Vec<f64>> = query
2062 .query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite))?
2063 .collect();
2064
2065 match bad_type.unwrap_err() {
2066 CustomError::Sqlite(Error::InvalidColumnType(..)) => (),
2067 err => panic!("Unexpected error {err}"),
2068 }
2069
2070 let bad_idx: CustomResult<Vec<String>> = query
2071 .query_and_then([], |row| row.get(3).map_err(CustomError::Sqlite))?
2072 .collect();
2073
2074 match bad_idx.unwrap_err() {
2075 CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
2076 err => panic!("Unexpected error {err}"),
2077 }
2078
2079 let non_sqlite_err: CustomResult<Vec<String>> = query
2080 .query_and_then([], |_| Err(CustomError::SomeError))?
2081 .collect();
2082
2083 match non_sqlite_err.unwrap_err() {
2084 CustomError::SomeError => (),
2085 err => panic!("Unexpected error {err}"),
2086 }
2087 Ok(())
2088 }
2089
2090 #[test]
2091 fn test_query_row_and_then_custom_error() -> CustomResult<()> {
2092 let db = Connection::open_in_memory()?;
2093 let sql = "BEGIN;
2094 CREATE TABLE foo(x INTEGER, y TEXT);
2095 INSERT INTO foo VALUES(4, \"hello\");
2096 END;";
2097 db.execute_batch(sql)?;
2098
2099 let query = "SELECT x, y FROM foo ORDER BY x DESC";
2100 let results: CustomResult<String> =
2101 db.query_row_and_then(query, [], |row| row.get(1).map_err(CustomError::Sqlite));
2102
2103 assert_eq!(results?, "hello");
2104 Ok(())
2105 }
2106
2107 #[test]
2108 fn test_query_row_and_then_custom_error_fails() -> Result<()> {
2109 let db = Connection::open_in_memory()?;
2110 let sql = "BEGIN;
2111 CREATE TABLE foo(x INTEGER, y TEXT);
2112 INSERT INTO foo VALUES(4, \"hello\");
2113 END;";
2114 db.execute_batch(sql)?;
2115
2116 let query = "SELECT x, y FROM foo ORDER BY x DESC";
2117 let bad_type: CustomResult<f64> =
2118 db.query_row_and_then(query, [], |row| row.get(1).map_err(CustomError::Sqlite));
2119
2120 match bad_type.unwrap_err() {
2121 CustomError::Sqlite(Error::InvalidColumnType(..)) => (),
2122 err => panic!("Unexpected error {err}"),
2123 }
2124
2125 let bad_idx: CustomResult<String> =
2126 db.query_row_and_then(query, [], |row| row.get(3).map_err(CustomError::Sqlite));
2127
2128 match bad_idx.unwrap_err() {
2129 CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
2130 err => panic!("Unexpected error {err}"),
2131 }
2132
2133 let non_sqlite_err: CustomResult<String> =
2134 db.query_row_and_then(query, [], |_| Err(CustomError::SomeError));
2135
2136 match non_sqlite_err.unwrap_err() {
2137 CustomError::SomeError => (),
2138 err => panic!("Unexpected error {err}"),
2139 }
2140 Ok(())
2141 }
2142 }
2143
2144 #[test]
2145 fn test_dynamic() -> Result<()> {
2146 let db = Connection::open_in_memory()?;
2147 let sql = "BEGIN;
2148 CREATE TABLE foo(x INTEGER, y TEXT);
2149 INSERT INTO foo VALUES(4, \"hello\");
2150 END;";
2151 db.execute_batch(sql)?;
2152
2153 db.query_row("SELECT * FROM foo", [], |r| {
2154 assert_eq!(2, r.as_ref().column_count());
2155 Ok(())
2156 })
2157 }
2158 #[test]
2159 fn test_dyn_box() -> Result<()> {
2160 let db = Connection::open_in_memory()?;
2161 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
2162 let b: Box<dyn ToSql> = Box::new(5);
2163 db.execute("INSERT INTO foo VALUES(?1)", [b])?;
2164 db.query_row("SELECT x FROM foo", [], |r| {
2165 assert_eq!(5, r.get_unwrap::<_, i32>(0));
2166 Ok(())
2167 })
2168 }
2169
2170 #[test]
2171 fn test_params() -> Result<()> {
2172 let db = Connection::open_in_memory()?;
2173 db.query_row(
2174 "SELECT
2175 ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10,
2176 ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19, ?20,
2177 ?21, ?22, ?23, ?24, ?25, ?26, ?27, ?28, ?29, ?30,
2178 ?31, ?32, ?33, ?34;",
2179 params![
2180 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,
2181 1, 1, 1, 1, 1, 1,
2182 ],
2183 |r| {
2184 assert_eq!(1, r.get_unwrap::<_, i32>(0));
2185 Ok(())
2186 },
2187 )
2188 }
2189
2190 #[test]
2191 fn test_alter_table() -> Result<()> {
2192 let db = Connection::open_in_memory()?;
2193 db.execute_batch("CREATE TABLE x(t);")?;
2194 db.execute("ALTER TABLE x RENAME TO y;", [])?;
2196 Ok(())
2197 }
2198
2199 #[test]
2200 fn test_batch() -> Result<()> {
2201 let db = Connection::open_in_memory()?;
2202 let sql = r"
2203 CREATE TABLE tbl1 (col);
2204 CREATE TABLE tbl2 (col);
2205 ";
2206 let mut batch = Batch::new(&db, sql);
2207 while let Some(mut stmt) = batch.next()? {
2208 stmt.execute([])?;
2209 }
2210 Ok(())
2211 }
2212
2213 #[test]
2214 fn test_invalid_batch() -> Result<()> {
2215 let db = Connection::open_in_memory()?;
2216 let sql = r"
2217 PRAGMA test1;
2218 PRAGMA test2=?;
2219 PRAGMA test3;
2220 ";
2221 let mut batch = Batch::new(&db, sql);
2222 assert!(batch.next().is_ok());
2223 assert!(batch.next().is_err());
2224 assert!(batch.next().is_err());
2225 assert!(Batch::new(&db, sql).count().is_err());
2226 Ok(())
2227 }
2228
2229 #[test]
2230 #[cfg(feature = "modern_sqlite")]
2231 fn test_returning() -> Result<()> {
2232 let db = Connection::open_in_memory()?;
2233 db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)")?;
2234 let row_id =
2235 db.one_column::<i64, _>("INSERT INTO foo DEFAULT VALUES RETURNING ROWID", [])?;
2236 assert_eq!(row_id, 1);
2237 Ok(())
2238 }
2239
2240 #[test]
2241 fn test_cache_flush() -> Result<()> {
2242 let db = Connection::open_in_memory()?;
2243 db.cache_flush()
2244 }
2245
2246 #[test]
2247 fn db_readonly() -> Result<()> {
2248 let db = Connection::open_in_memory()?;
2249 assert!(!db.is_readonly(MAIN_DB)?);
2250 Ok(())
2251 }
2252
2253 #[test]
2254 #[cfg(feature = "rusqlite-macros")]
2255 fn prepare_and_bind() -> Result<()> {
2256 let db = Connection::open_in_memory()?;
2257 let name = "Lisa";
2258 let age = 8;
2259 let mut stmt = prepare_and_bind!(db, "SELECT $name, $age;");
2260 let (v1, v2) = stmt
2261 .raw_query()
2262 .next()
2263 .and_then(|o| o.ok_or(Error::QueryReturnedNoRows))
2264 .and_then(|r| Ok((r.get::<_, String>(0)?, r.get::<_, i64>(1)?)))?;
2265 assert_eq!((v1.as_str(), v2), (name, age));
2266 Ok(())
2267 }
2268
2269 #[test]
2270 #[cfg(feature = "modern_sqlite")]
2271 fn test_db_name() -> Result<()> {
2272 let db = Connection::open_in_memory()?;
2273 assert_eq!(db.db_name(0)?, "main");
2274 assert_eq!(db.db_name(1)?, "temp");
2275 assert_eq!(db.db_name(2), Err(Error::InvalidDatabaseIndex(2)));
2276 db.execute_batch("ATTACH DATABASE ':memory:' AS xyz;")?;
2277 assert_eq!(db.db_name(2)?, "xyz");
2278 Ok(())
2279 }
2280
2281 #[test]
2282 #[cfg(feature = "modern_sqlite")]
2283 fn test_is_interrupted() -> Result<()> {
2284 let db = Connection::open_in_memory()?;
2285 assert!(!db.is_interrupted());
2286 db.get_interrupt_handle().interrupt();
2287 assert!(db.is_interrupted());
2288 Ok(())
2289 }
2290
2291 #[test]
2292 fn release_memory() -> Result<()> {
2293 let db = Connection::open_in_memory()?;
2294 db.release_memory()
2295 }
2296}