1#![warn(missing_docs)]
55#![cfg_attr(docsrs, feature(doc_cfg))]
56
57pub use libsqlite3_sys as ffi;
58
59use std::cell::RefCell;
60use std::default::Default;
61use std::ffi::{CStr, CString};
62use std::fmt;
63use std::os::raw::{c_char, c_int};
64
65use std::path::Path;
66use std::result;
67use std::str;
68use std::sync::atomic::Ordering;
69use std::sync::{Arc, Mutex};
70
71use crate::cache::StatementCache;
72use crate::inner_connection::{InnerConnection, BYPASS_SQLITE_INIT};
73use crate::raw_statement::RawStatement;
74use crate::types::ValueRef;
75
76pub use crate::cache::CachedStatement;
77#[cfg(feature = "column_decltype")]
78pub use crate::column::Column;
79pub use crate::error::{to_sqlite_error, Error};
80pub use crate::ffi::ErrorCode;
81#[cfg(feature = "load_extension")]
82pub use crate::load_extension_guard::LoadExtensionGuard;
83pub use crate::params::{params_from_iter, Params, ParamsFromIter};
84pub use crate::row::{AndThenRows, Map, MappedRows, Row, RowIndex, Rows};
85pub use crate::statement::{Statement, StatementStatus};
86#[cfg(feature = "modern_sqlite")]
87pub use crate::transaction::TransactionState;
88pub use crate::transaction::{DropBehavior, Savepoint, Transaction, TransactionBehavior};
89pub use crate::types::ToSql;
90pub use crate::version::*;
91#[cfg(feature = "rusqlite-macros")]
92#[doc(hidden)]
93pub use rusqlite_macros::__bind;
94
95mod error;
96
97#[cfg(feature = "backup")]
98#[cfg_attr(docsrs, doc(cfg(feature = "backup")))]
99pub mod backup;
100#[cfg(feature = "blob")]
101#[cfg_attr(docsrs, doc(cfg(feature = "blob")))]
102pub mod blob;
103mod busy;
104mod cache;
105#[cfg(feature = "collation")]
106#[cfg_attr(docsrs, doc(cfg(feature = "collation")))]
107mod collation;
108mod column;
109pub mod config;
110#[cfg(any(feature = "functions", feature = "vtab"))]
111mod context;
112#[cfg(feature = "functions")]
113#[cfg_attr(docsrs, doc(cfg(feature = "functions")))]
114pub mod functions;
115#[cfg(feature = "hooks")]
116#[cfg_attr(docsrs, doc(cfg(feature = "hooks")))]
117pub mod hooks;
118mod inner_connection;
119#[cfg(feature = "limits")]
120#[cfg_attr(docsrs, doc(cfg(feature = "limits")))]
121pub mod limits;
122#[cfg(feature = "load_extension")]
123mod load_extension_guard;
124mod params;
125mod pragma;
126mod raw_statement;
127mod row;
128#[cfg(feature = "serialize")]
129#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
130pub mod serialize;
131#[cfg(feature = "session")]
132#[cfg_attr(docsrs, doc(cfg(feature = "session")))]
133pub mod session;
134mod statement;
135#[cfg(feature = "trace")]
136#[cfg_attr(docsrs, doc(cfg(feature = "trace")))]
137pub mod trace;
138mod transaction;
139pub mod types;
140#[cfg(feature = "unlock_notify")]
141mod unlock_notify;
142mod version;
143#[cfg(feature = "vtab")]
144#[cfg_attr(docsrs, doc(cfg(feature = "vtab")))]
145pub mod vtab;
146
147pub(crate) mod util;
148pub(crate) use util::SmallCString;
149
150const STATEMENT_CACHE_DEFAULT_CAPACITY: usize = 16;
152
153#[macro_export]
176macro_rules! params {
177 () => {
178 &[] as &[&dyn $crate::ToSql]
179 };
180 ($($param:expr),+ $(,)?) => {
181 &[$(&$param as &dyn $crate::ToSql),+] as &[&dyn $crate::ToSql]
182 };
183}
184
185#[macro_export]
213macro_rules! named_params {
214 () => {
215 &[] as &[(&str, &dyn $crate::ToSql)]
216 };
217 ($($param_name:literal: $param_val:expr),+ $(,)?) => {
220 &[$(($param_name, &$param_val as &dyn $crate::ToSql)),+] as &[(&str, &dyn $crate::ToSql)]
221 };
222}
223
224#[cfg(feature = "rusqlite-macros")]
243#[cfg_attr(docsrs, doc(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#[cfg_attr(docsrs, doc(cfg(feature = "rusqlite-macros")))]
260#[macro_export]
261macro_rules! prepare_cached_and_bind {
262 ($conn:expr, $sql:literal) => {{
263 let mut stmt = $conn.prepare_cached($sql)?;
264 $crate::__bind!(stmt $sql);
265 stmt
266 }};
267}
268
269pub type Result<T, E = Error> = result::Result<T, E>;
271
272pub trait OptionalExtension<T> {
274 fn optional(self) -> Result<Option<T>>;
280}
281
282impl<T> OptionalExtension<T> for Result<T> {
283 fn optional(self) -> Result<Option<T>> {
284 match self {
285 Ok(value) => Ok(Some(value)),
286 Err(Error::QueryReturnedNoRows) => Ok(None),
287 Err(e) => Err(e),
288 }
289 }
290}
291
292unsafe fn errmsg_to_string(errmsg: *const c_char) -> String {
293 let c_slice = CStr::from_ptr(errmsg).to_bytes();
294 String::from_utf8_lossy(c_slice).into_owned()
295}
296
297fn str_to_cstring(s: &str) -> Result<SmallCString> {
298 Ok(SmallCString::new(s)?)
299}
300
301fn str_for_sqlite(s: &[u8]) -> Result<(*const c_char, c_int, ffi::sqlite3_destructor_type)> {
308 let len = len_as_c_int(s.len())?;
309 let (ptr, dtor_info) = if len != 0 {
310 (s.as_ptr().cast::<c_char>(), ffi::SQLITE_TRANSIENT())
311 } else {
312 ("".as_ptr().cast::<c_char>(), ffi::SQLITE_STATIC())
314 };
315 Ok((ptr, len, dtor_info))
316}
317
318fn len_as_c_int(len: usize) -> Result<c_int> {
321 if len >= (c_int::MAX as usize) {
322 Err(Error::SqliteFailure(
323 ffi::Error::new(ffi::SQLITE_TOOBIG),
324 None,
325 ))
326 } else {
327 Ok(len as c_int)
328 }
329}
330
331#[cfg(unix)]
332fn path_to_cstring(p: &Path) -> Result<CString> {
333 use std::os::unix::ffi::OsStrExt;
334 Ok(CString::new(p.as_os_str().as_bytes())?)
335}
336
337#[cfg(not(unix))]
338fn path_to_cstring(p: &Path) -> Result<CString> {
339 let s = p.to_str().ok_or_else(|| Error::InvalidPath(p.to_owned()))?;
340 Ok(CString::new(s)?)
341}
342
343#[derive(Copy, Clone, Debug)]
345pub enum DatabaseName<'a> {
346 Main,
348
349 Temp,
351
352 Attached(&'a str),
354}
355
356pub const MAIN_DB: DatabaseName<'static> = DatabaseName::Main;
358
359pub const TEMP_DB: DatabaseName<'static> = DatabaseName::Temp;
361
362impl DatabaseName<'_> {
365 #[inline]
366 fn as_cstring(&self) -> Result<SmallCString> {
367 use self::DatabaseName::{Attached, Main, Temp};
368 match *self {
369 Main => str_to_cstring("main"),
370 Temp => str_to_cstring("temp"),
371 Attached(s) => str_to_cstring(s),
372 }
373 }
374}
375
376pub struct Connection {
378 db: RefCell<InnerConnection>,
379 cache: StatementCache,
380}
381
382unsafe impl Send for Connection {}
383
384impl Drop for Connection {
385 #[inline]
386 fn drop(&mut self) {
387 self.flush_prepared_statement_cache();
388 }
389}
390
391impl Connection {
392 #[inline]
445 pub fn open<P: AsRef<Path>>(path: P) -> Result<Connection> {
446 let flags = OpenFlags::default();
447 Connection::open_with_flags(path, flags)
448 }
449
450 #[inline]
456 pub fn open_in_memory() -> Result<Connection> {
457 let flags = OpenFlags::default();
458 Connection::open_in_memory_with_flags(flags)
459 }
460
461 #[inline]
471 pub fn open_with_flags<P: AsRef<Path>>(path: P, flags: OpenFlags) -> Result<Connection> {
472 let c_path = path_to_cstring(path.as_ref())?;
473 InnerConnection::open_with_flags(&c_path, flags, None).map(|db| Connection {
474 db: RefCell::new(db),
475 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
476 })
477 }
478
479 #[inline]
490 pub fn open_with_flags_and_vfs<P: AsRef<Path>>(
491 path: P,
492 flags: OpenFlags,
493 vfs: &str,
494 ) -> Result<Connection> {
495 let c_path = path_to_cstring(path.as_ref())?;
496 let c_vfs = str_to_cstring(vfs)?;
497 InnerConnection::open_with_flags(&c_path, flags, Some(&c_vfs)).map(|db| Connection {
498 db: RefCell::new(db),
499 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
500 })
501 }
502
503 #[inline]
512 pub fn open_in_memory_with_flags(flags: OpenFlags) -> Result<Connection> {
513 Connection::open_with_flags(":memory:", flags)
514 }
515
516 #[inline]
527 pub fn open_in_memory_with_flags_and_vfs(flags: OpenFlags, vfs: &str) -> Result<Connection> {
528 Connection::open_with_flags_and_vfs(":memory:", flags, vfs)
529 }
530
531 pub fn execute_batch(&self, sql: &str) -> Result<()> {
553 let mut sql = sql;
554 while !sql.is_empty() {
555 let stmt = self.prepare(sql)?;
556 if !stmt.stmt.is_null() && stmt.step()? && cfg!(feature = "extra_check") {
557 return Err(Error::ExecuteReturnedResults);
559 }
560 let tail = stmt.stmt.tail();
561 if tail == 0 || tail >= sql.len() {
562 break;
563 }
564 sql = &sql[tail..];
565 }
566 Ok(())
567 }
568
569 #[inline]
620 pub fn execute<P: Params>(&self, sql: &str, params: P) -> Result<usize> {
621 self.prepare(sql)
622 .and_then(|mut stmt| stmt.check_no_tail().and_then(|()| stmt.execute(params)))
623 }
624
625 #[inline]
633 pub fn path(&self) -> Option<&str> {
634 unsafe {
635 let db = self.handle();
636 let db_name = DatabaseName::Main.as_cstring().unwrap();
637 let db_filename = ffi::sqlite3_db_filename(db, db_name.as_ptr());
638 if db_filename.is_null() {
639 None
640 } else {
641 CStr::from_ptr(db_filename).to_str().ok()
642 }
643 }
644 }
645
646 #[inline]
651 #[cfg(feature = "release_memory")]
652 pub fn release_memory(&self) -> Result<()> {
653 self.db.borrow_mut().release_memory()
654 }
655
656 #[inline]
661 pub fn last_insert_rowid(&self) -> i64 {
662 self.db.borrow_mut().last_insert_rowid()
663 }
664
665 #[inline]
693 pub fn query_row<T, P, F>(&self, sql: &str, params: P, f: F) -> Result<T>
694 where
695 P: Params,
696 F: FnOnce(&Row<'_>) -> Result<T>,
697 {
698 let mut stmt = self.prepare(sql)?;
699 stmt.check_no_tail()?;
700 stmt.query_row(params, f)
701 }
702
703 #[cfg(test)]
705 pub(crate) fn one_column<T: types::FromSql>(&self, sql: &str) -> Result<T> {
706 self.query_row(sql, [], |r| r.get(0))
707 }
708
709 #[inline]
735 pub fn query_row_and_then<T, E, P, F>(&self, sql: &str, params: P, f: F) -> Result<T, E>
736 where
737 P: Params,
738 F: FnOnce(&Row<'_>) -> Result<T, E>,
739 E: From<Error>,
740 {
741 let mut stmt = self.prepare(sql)?;
742 stmt.check_no_tail()?;
743 let mut rows = stmt.query(params)?;
744
745 rows.get_expected_row().map_err(E::from).and_then(f)
746 }
747
748 #[inline]
767 pub fn prepare(&self, sql: &str) -> Result<Statement<'_>> {
768 self.prepare_with_flags(sql, PrepFlags::default())
769 }
770
771 #[inline]
778 pub fn prepare_with_flags(&self, sql: &str, flags: PrepFlags) -> Result<Statement<'_>> {
779 self.db.borrow_mut().prepare(self, sql, flags)
780 }
781
782 #[inline]
792 pub fn close(self) -> Result<(), (Connection, Error)> {
793 self.flush_prepared_statement_cache();
794 let r = self.db.borrow_mut().close();
795 r.map_err(move |err| (self, err))
796 }
797
798 #[cfg(feature = "load_extension")]
851 #[cfg_attr(docsrs, doc(cfg(feature = "load_extension")))]
852 #[inline]
853 pub unsafe fn load_extension_enable(&self) -> Result<()> {
854 self.db.borrow_mut().enable_load_extension(1)
855 }
856
857 #[cfg(feature = "load_extension")]
865 #[cfg_attr(docsrs, doc(cfg(feature = "load_extension")))]
866 #[inline]
867 pub fn load_extension_disable(&self) -> Result<()> {
868 unsafe { self.db.borrow_mut().enable_load_extension(0) }
870 }
871
872 #[cfg(feature = "load_extension")]
908 #[cfg_attr(docsrs, doc(cfg(feature = "load_extension")))]
909 #[inline]
910 pub unsafe fn load_extension<P: AsRef<Path>>(
911 &self,
912 dylib_path: P,
913 entry_point: Option<&str>,
914 ) -> Result<()> {
915 self.db
916 .borrow_mut()
917 .load_extension(dylib_path.as_ref(), entry_point)
918 }
919
920 #[inline]
934 pub unsafe fn handle(&self) -> *mut ffi::sqlite3 {
935 self.db.borrow().db()
936 }
937
938 #[inline]
947 pub unsafe fn from_handle(db: *mut ffi::sqlite3) -> Result<Connection> {
948 let db = InnerConnection::new(db, false);
949 Ok(Connection {
950 db: RefCell::new(db),
951 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
952 })
953 }
954
955 #[cfg(feature = "loadable_extension")]
957 #[cfg_attr(docsrs, doc(cfg(feature = "loadable_extension")))]
958 pub unsafe fn extension_init2(
959 db: *mut ffi::sqlite3,
960 p_api: *mut ffi::sqlite3_api_routines,
961 ) -> Result<Connection> {
962 ffi::rusqlite_extension_init2(p_api)?;
963 Connection::from_handle(db)
964 }
965
966 #[inline]
979 pub unsafe fn from_handle_owned(db: *mut ffi::sqlite3) -> Result<Connection> {
980 let db = InnerConnection::new(db, true);
981 Ok(Connection {
982 db: RefCell::new(db),
983 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
984 })
985 }
986
987 #[inline]
990 pub fn get_interrupt_handle(&self) -> InterruptHandle {
991 self.db.borrow().get_interrupt_handle()
992 }
993
994 #[inline]
995 fn decode_result(&self, code: c_int) -> Result<()> {
996 self.db.borrow().decode_result(code)
997 }
998
999 #[inline]
1005 pub fn changes(&self) -> u64 {
1006 self.db.borrow().changes()
1007 }
1008
1009 #[inline]
1012 pub fn is_autocommit(&self) -> bool {
1013 self.db.borrow().is_autocommit()
1014 }
1015
1016 #[inline]
1018 pub fn is_busy(&self) -> bool {
1019 self.db.borrow().is_busy()
1020 }
1021
1022 pub fn cache_flush(&self) -> Result<()> {
1024 self.db.borrow_mut().cache_flush()
1025 }
1026
1027 pub fn is_readonly(&self, db_name: DatabaseName<'_>) -> Result<bool> {
1029 self.db.borrow().db_readonly(db_name)
1030 }
1031}
1032
1033impl fmt::Debug for Connection {
1034 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1035 f.debug_struct("Connection")
1036 .field("path", &self.path())
1037 .finish()
1038 }
1039}
1040
1041#[derive(Debug)]
1059pub struct Batch<'conn, 'sql> {
1060 conn: &'conn Connection,
1061 sql: &'sql str,
1062 tail: usize,
1063}
1064
1065impl<'conn, 'sql> Batch<'conn, 'sql> {
1066 pub fn new(conn: &'conn Connection, sql: &'sql str) -> Batch<'conn, 'sql> {
1068 Batch { conn, sql, tail: 0 }
1069 }
1070
1071 #[allow(clippy::should_implement_trait)] pub fn next(&mut self) -> Result<Option<Statement<'conn>>> {
1076 while self.tail < self.sql.len() {
1077 let sql = &self.sql[self.tail..];
1078 let next = self.conn.prepare(sql)?;
1079 let tail = next.stmt.tail();
1080 if tail == 0 {
1081 self.tail = self.sql.len();
1082 } else {
1083 self.tail += tail;
1084 }
1085 if next.stmt.is_null() {
1086 continue;
1087 }
1088 return Ok(Some(next));
1089 }
1090 Ok(None)
1091 }
1092}
1093
1094impl<'conn> Iterator for Batch<'conn, '_> {
1095 type Item = Result<Statement<'conn>>;
1096
1097 fn next(&mut self) -> Option<Result<Statement<'conn>>> {
1098 self.next().transpose()
1099 }
1100}
1101
1102bitflags::bitflags! {
1103 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1110 #[repr(C)]
1111 pub struct OpenFlags: ::std::os::raw::c_int {
1112 const SQLITE_OPEN_READ_ONLY = ffi::SQLITE_OPEN_READONLY;
1115 const SQLITE_OPEN_READ_WRITE = ffi::SQLITE_OPEN_READWRITE;
1119 const SQLITE_OPEN_CREATE = ffi::SQLITE_OPEN_CREATE;
1121 const SQLITE_OPEN_URI = ffi::SQLITE_OPEN_URI;
1123 const SQLITE_OPEN_MEMORY = ffi::SQLITE_OPEN_MEMORY;
1125 const SQLITE_OPEN_NO_MUTEX = ffi::SQLITE_OPEN_NOMUTEX;
1134 const SQLITE_OPEN_FULL_MUTEX = ffi::SQLITE_OPEN_FULLMUTEX;
1158 const SQLITE_OPEN_SHARED_CACHE = 0x0002_0000;
1165 const SQLITE_OPEN_PRIVATE_CACHE = 0x0004_0000;
1167 const SQLITE_OPEN_NOFOLLOW = 0x0100_0000;
1169 const SQLITE_OPEN_EXRESCODE = 0x0200_0000;
1171 }
1172}
1173
1174impl Default for OpenFlags {
1175 #[inline]
1176 fn default() -> OpenFlags {
1177 OpenFlags::SQLITE_OPEN_READ_WRITE
1180 | OpenFlags::SQLITE_OPEN_CREATE
1181 | OpenFlags::SQLITE_OPEN_NO_MUTEX
1182 | OpenFlags::SQLITE_OPEN_URI
1183 }
1184}
1185
1186bitflags::bitflags! {
1187 #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
1190 #[repr(C)]
1191 pub struct PrepFlags: ::std::os::raw::c_uint {
1192 const SQLITE_PREPARE_PERSISTENT = 0x01;
1194 const SQLITE_PREPARE_NO_VTAB = 0x04;
1196 }
1197}
1198
1199pub unsafe fn bypass_sqlite_initialization() {
1219 BYPASS_SQLITE_INIT.store(true, Ordering::Relaxed);
1220}
1221
1222pub struct InterruptHandle {
1224 db_lock: Arc<Mutex<*mut ffi::sqlite3>>,
1225}
1226
1227unsafe impl Send for InterruptHandle {}
1228unsafe impl Sync for InterruptHandle {}
1229
1230impl InterruptHandle {
1231 pub fn interrupt(&self) {
1234 let db_handle = self.db_lock.lock().unwrap();
1235 if !db_handle.is_null() {
1236 unsafe { ffi::sqlite3_interrupt(*db_handle) }
1237 }
1238 }
1239}
1240
1241#[cfg(doctest)]
1242doc_comment::doctest!("../README.md");
1243
1244#[cfg(test)]
1245mod test {
1246 use super::*;
1247 use crate::ffi;
1248 use fallible_iterator::FallibleIterator;
1249 use std::error::Error as StdError;
1250 use std::fmt;
1251
1252 #[allow(
1256 dead_code,
1257 unconditional_recursion,
1258 clippy::extra_unused_type_parameters
1259 )]
1260 fn ensure_send<T: Send>() {
1261 ensure_send::<Connection>();
1262 ensure_send::<InterruptHandle>();
1263 }
1264
1265 #[allow(
1266 dead_code,
1267 unconditional_recursion,
1268 clippy::extra_unused_type_parameters
1269 )]
1270 fn ensure_sync<T: Sync>() {
1271 ensure_sync::<InterruptHandle>();
1272 }
1273
1274 fn checked_memory_handle() -> Connection {
1275 Connection::open_in_memory().unwrap()
1276 }
1277
1278 #[test]
1279 fn test_concurrent_transactions_busy_commit() -> Result<()> {
1280 use std::time::Duration;
1281 let tmp = tempfile::tempdir().unwrap();
1282 let path = tmp.path().join("transactions.db3");
1283
1284 Connection::open(&path)?.execute_batch(
1285 "
1286 BEGIN; CREATE TABLE foo(x INTEGER);
1287 INSERT INTO foo VALUES(42); END;",
1288 )?;
1289
1290 let mut db1 = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_WRITE)?;
1291 let mut db2 = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_ONLY)?;
1292
1293 db1.busy_timeout(Duration::from_millis(0))?;
1294 db2.busy_timeout(Duration::from_millis(0))?;
1295
1296 {
1297 let tx1 = db1.transaction()?;
1298 let tx2 = db2.transaction()?;
1299
1300 tx1.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))?;
1302 tx2.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))?;
1303
1304 tx1.execute("INSERT INTO foo VALUES(?1)", [1])?;
1305 let _ = tx2.execute("INSERT INTO foo VALUES(?1)", [2]);
1306
1307 let _ = tx1.commit();
1308 let _ = tx2.commit();
1309 }
1310
1311 let _ = db1
1312 .transaction()
1313 .expect("commit should have closed transaction");
1314 let _ = db2
1315 .transaction()
1316 .expect("commit should have closed transaction");
1317 Ok(())
1318 }
1319
1320 #[test]
1321 fn test_persistence() -> Result<()> {
1322 let temp_dir = tempfile::tempdir().unwrap();
1323 let path = temp_dir.path().join("test.db3");
1324
1325 {
1326 let db = Connection::open(&path)?;
1327 let sql = "BEGIN;
1328 CREATE TABLE foo(x INTEGER);
1329 INSERT INTO foo VALUES(42);
1330 END;";
1331 db.execute_batch(sql)?;
1332 }
1333
1334 let path_string = path.to_str().unwrap();
1335 let db = Connection::open(path_string)?;
1336 let the_answer: i64 = db.one_column("SELECT x FROM foo")?;
1337
1338 assert_eq!(42i64, the_answer);
1339 Ok(())
1340 }
1341
1342 #[test]
1343 fn test_open() {
1344 Connection::open_in_memory().unwrap();
1345
1346 let db = checked_memory_handle();
1347 db.close().unwrap();
1348 }
1349
1350 #[test]
1351 fn test_path() -> Result<()> {
1352 let tmp = tempfile::tempdir().unwrap();
1353 let db = Connection::open("")?;
1354 assert_eq!(Some(""), db.path());
1355 let db = Connection::open_in_memory()?;
1356 assert_eq!(Some(""), db.path());
1357 let db = Connection::open("file:dummy.db?mode=memory&cache=shared")?;
1358 assert_eq!(Some(""), db.path());
1359 let path = tmp.path().join("file.db");
1360 let db = Connection::open(path)?;
1361 assert!(db.path().map(|p| p.ends_with("file.db")).unwrap_or(false));
1362 Ok(())
1363 }
1364
1365 #[test]
1366 fn test_open_failure() {
1367 let filename = "no_such_file.db";
1368 let result = Connection::open_with_flags(filename, OpenFlags::SQLITE_OPEN_READ_ONLY);
1369 let err = result.unwrap_err();
1370 if let Error::SqliteFailure(e, Some(msg)) = err {
1371 assert_eq!(ErrorCode::CannotOpen, e.code);
1372 assert_eq!(ffi::SQLITE_CANTOPEN, e.extended_code);
1373 assert!(
1374 msg.contains(filename),
1375 "error message '{msg}' does not contain '{filename}'"
1376 );
1377 } else {
1378 panic!("SqliteFailure expected");
1379 }
1380 }
1381
1382 #[cfg(unix)]
1383 #[test]
1384 fn test_invalid_unicode_file_names() -> Result<()> {
1385 use std::ffi::OsStr;
1386 use std::fs::File;
1387 use std::os::unix::ffi::OsStrExt;
1388 let temp_dir = tempfile::tempdir().unwrap();
1389
1390 let path = temp_dir.path();
1391 if File::create(path.join(OsStr::from_bytes(&[0xFE]))).is_err() {
1392 return Ok(());
1394 }
1395 let db_path = path.join(OsStr::from_bytes(&[0xFF]));
1396 {
1397 let db = Connection::open(&db_path)?;
1398 let sql = "BEGIN;
1399 CREATE TABLE foo(x INTEGER);
1400 INSERT INTO foo VALUES(42);
1401 END;";
1402 db.execute_batch(sql)?;
1403 }
1404
1405 let db = Connection::open(&db_path)?;
1406 let the_answer: i64 = db.one_column("SELECT x FROM foo")?;
1407
1408 assert_eq!(42i64, the_answer);
1409 Ok(())
1410 }
1411
1412 #[test]
1413 fn test_close_retry() -> Result<()> {
1414 let db = Connection::open_in_memory()?;
1415
1416 let raw_stmt = {
1420 use super::str_to_cstring;
1421 use std::os::raw::c_int;
1422 use std::ptr;
1423
1424 let raw_db = db.db.borrow_mut().db;
1425 let sql = "SELECT 1";
1426 let mut raw_stmt: *mut ffi::sqlite3_stmt = ptr::null_mut();
1427 let cstring = str_to_cstring(sql)?;
1428 let rc = unsafe {
1429 ffi::sqlite3_prepare_v2(
1430 raw_db,
1431 cstring.as_ptr(),
1432 (sql.len() + 1) as c_int,
1433 &mut raw_stmt,
1434 ptr::null_mut(),
1435 )
1436 };
1437 assert_eq!(rc, ffi::SQLITE_OK);
1438 raw_stmt
1439 };
1440
1441 let (db, _) = db.close().unwrap_err();
1444 let (db, _) = db.close().unwrap_err();
1445 let (db, _) = db.close().unwrap_err();
1446
1447 assert_eq!(ffi::SQLITE_OK, unsafe { ffi::sqlite3_finalize(raw_stmt) });
1449
1450 db.close().unwrap();
1451 Ok(())
1452 }
1453
1454 #[test]
1455 fn test_open_with_flags() {
1456 for bad_flags in &[
1457 OpenFlags::empty(),
1458 OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_READ_WRITE,
1459 OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_CREATE,
1460 ] {
1461 Connection::open_in_memory_with_flags(*bad_flags).unwrap_err();
1462 }
1463 }
1464
1465 #[test]
1466 fn test_execute_batch() -> Result<()> {
1467 let db = Connection::open_in_memory()?;
1468 let sql = "BEGIN;
1469 CREATE TABLE foo(x INTEGER);
1470 INSERT INTO foo VALUES(1);
1471 INSERT INTO foo VALUES(2);
1472 INSERT INTO foo VALUES(3);
1473 INSERT INTO foo VALUES(4);
1474 END;";
1475 db.execute_batch(sql)?;
1476
1477 db.execute_batch("UPDATE foo SET x = 3 WHERE x < 3")?;
1478
1479 db.execute_batch("INVALID SQL").unwrap_err();
1480 Ok(())
1481 }
1482
1483 #[test]
1484 fn test_execute() -> Result<()> {
1485 let db = Connection::open_in_memory()?;
1486 db.execute_batch("CREATE TABLE foo(x INTEGER)")?;
1487
1488 assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?1)", [1i32])?);
1489 assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?1)", [2i32])?);
1490
1491 assert_eq!(3i32, db.one_column::<i32>("SELECT SUM(x) FROM foo")?);
1492 Ok(())
1493 }
1494
1495 #[test]
1496 #[cfg(feature = "extra_check")]
1497 fn test_execute_select_with_no_row() {
1498 let db = checked_memory_handle();
1499 let err = db.execute("SELECT 1 WHERE 1 < ?1", [1i32]).unwrap_err();
1500 assert_eq!(
1501 err,
1502 Error::ExecuteReturnedResults,
1503 "Unexpected error: {err}"
1504 );
1505 }
1506
1507 #[test]
1508 fn test_execute_select_with_row() {
1509 let db = checked_memory_handle();
1510 let err = db.execute("SELECT 1", []).unwrap_err();
1511 assert_eq!(err, Error::ExecuteReturnedResults);
1512 }
1513
1514 #[test]
1515 #[cfg(feature = "extra_check")]
1516 fn test_execute_multiple() {
1517 let db = checked_memory_handle();
1518 let err = db
1519 .execute(
1520 "CREATE TABLE foo(x INTEGER); CREATE TABLE foo(x INTEGER)",
1521 [],
1522 )
1523 .unwrap_err();
1524 match err {
1525 Error::MultipleStatement => (),
1526 _ => panic!("Unexpected error: {err}"),
1527 }
1528 }
1529
1530 #[test]
1531 fn test_prepare_column_names() -> Result<()> {
1532 let db = Connection::open_in_memory()?;
1533 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1534
1535 let stmt = db.prepare("SELECT * FROM foo")?;
1536 assert_eq!(stmt.column_count(), 1);
1537 assert_eq!(stmt.column_names(), vec!["x"]);
1538
1539 let stmt = db.prepare("SELECT x AS a, x AS b FROM foo")?;
1540 assert_eq!(stmt.column_count(), 2);
1541 assert_eq!(stmt.column_names(), vec!["a", "b"]);
1542 Ok(())
1543 }
1544
1545 #[test]
1546 fn test_prepare_execute() -> Result<()> {
1547 let db = Connection::open_in_memory()?;
1548 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1549
1550 let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?1)")?;
1551 assert_eq!(insert_stmt.execute([1i32])?, 1);
1552 assert_eq!(insert_stmt.execute([2i32])?, 1);
1553 assert_eq!(insert_stmt.execute([3i32])?, 1);
1554
1555 assert_eq!(insert_stmt.execute(["hello"])?, 1);
1556 assert_eq!(insert_stmt.execute(["goodbye"])?, 1);
1557 assert_eq!(insert_stmt.execute([types::Null])?, 1);
1558
1559 let mut update_stmt = db.prepare("UPDATE foo SET x=?1 WHERE x<?2")?;
1560 assert_eq!(update_stmt.execute([3i32, 3i32])?, 2);
1561 assert_eq!(update_stmt.execute([3i32, 3i32])?, 0);
1562 assert_eq!(update_stmt.execute([8i32, 8i32])?, 3);
1563 Ok(())
1564 }
1565
1566 #[test]
1567 fn test_prepare_query() -> Result<()> {
1568 let db = Connection::open_in_memory()?;
1569 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1570
1571 let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?1)")?;
1572 assert_eq!(insert_stmt.execute([1i32])?, 1);
1573 assert_eq!(insert_stmt.execute([2i32])?, 1);
1574 assert_eq!(insert_stmt.execute([3i32])?, 1);
1575
1576 let mut query = db.prepare("SELECT x FROM foo WHERE x < ?1 ORDER BY x DESC")?;
1577 {
1578 let mut rows = query.query([4i32])?;
1579 let mut v = Vec::<i32>::new();
1580
1581 while let Some(row) = rows.next()? {
1582 v.push(row.get(0)?);
1583 }
1584
1585 assert_eq!(v, [3i32, 2, 1]);
1586 }
1587
1588 {
1589 let mut rows = query.query([3i32])?;
1590 let mut v = Vec::<i32>::new();
1591
1592 while let Some(row) = rows.next()? {
1593 v.push(row.get(0)?);
1594 }
1595
1596 assert_eq!(v, [2i32, 1]);
1597 }
1598 Ok(())
1599 }
1600
1601 #[test]
1602 fn test_query_map() -> Result<()> {
1603 let db = Connection::open_in_memory()?;
1604 let sql = "BEGIN;
1605 CREATE TABLE foo(x INTEGER, y TEXT);
1606 INSERT INTO foo VALUES(4, \"hello\");
1607 INSERT INTO foo VALUES(3, \", \");
1608 INSERT INTO foo VALUES(2, \"world\");
1609 INSERT INTO foo VALUES(1, \"!\");
1610 END;";
1611 db.execute_batch(sql)?;
1612
1613 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1614 let results: Result<Vec<String>> = query.query([])?.map(|row| row.get(1)).collect();
1615
1616 assert_eq!(results?.concat(), "hello, world!");
1617 Ok(())
1618 }
1619
1620 #[test]
1621 fn test_query_row() -> Result<()> {
1622 let db = Connection::open_in_memory()?;
1623 let sql = "BEGIN;
1624 CREATE TABLE foo(x INTEGER);
1625 INSERT INTO foo VALUES(1);
1626 INSERT INTO foo VALUES(2);
1627 INSERT INTO foo VALUES(3);
1628 INSERT INTO foo VALUES(4);
1629 END;";
1630 db.execute_batch(sql)?;
1631
1632 assert_eq!(10i64, db.one_column::<i64>("SELECT SUM(x) FROM foo")?);
1633
1634 let result: Result<i64> = db.one_column("SELECT x FROM foo WHERE x > 5");
1635 match result.unwrap_err() {
1636 Error::QueryReturnedNoRows => (),
1637 err => panic!("Unexpected error {err}"),
1638 }
1639
1640 let bad_query_result = db.query_row("NOT A PROPER QUERY; test123", [], |_| Ok(()));
1641
1642 bad_query_result.unwrap_err();
1643 Ok(())
1644 }
1645
1646 #[test]
1647 fn test_optional() -> Result<()> {
1648 let db = Connection::open_in_memory()?;
1649
1650 let result: Result<i64> = db.one_column("SELECT 1 WHERE 0 <> 0");
1651 let result = result.optional();
1652 match result? {
1653 None => (),
1654 _ => panic!("Unexpected result"),
1655 }
1656
1657 let result: Result<i64> = db.one_column("SELECT 1 WHERE 0 == 0");
1658 let result = result.optional();
1659 match result? {
1660 Some(1) => (),
1661 _ => panic!("Unexpected result"),
1662 }
1663
1664 let bad_query_result: Result<i64> = db.one_column("NOT A PROPER QUERY");
1665 let bad_query_result = bad_query_result.optional();
1666 bad_query_result.unwrap_err();
1667 Ok(())
1668 }
1669
1670 #[test]
1671 fn test_pragma_query_row() -> Result<()> {
1672 let db = Connection::open_in_memory()?;
1673 assert_eq!("memory", db.one_column::<String>("PRAGMA journal_mode")?);
1674 let mode = db.one_column::<String>("PRAGMA journal_mode=off")?;
1675 if cfg!(features = "bundled") {
1676 assert_eq!(mode, "off");
1677 } else {
1678 assert!(mode == "memory" || mode == "off", "Got mode {mode:?}");
1690 }
1691
1692 Ok(())
1693 }
1694
1695 #[test]
1696 fn test_prepare_failures() -> Result<()> {
1697 let db = Connection::open_in_memory()?;
1698 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1699
1700 let err = db.prepare("SELECT * FROM does_not_exist").unwrap_err();
1701 assert!(format!("{err}").contains("does_not_exist"));
1702 Ok(())
1703 }
1704
1705 #[test]
1706 fn test_last_insert_rowid() -> Result<()> {
1707 let db = Connection::open_in_memory()?;
1708 db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)")?;
1709 db.execute_batch("INSERT INTO foo DEFAULT VALUES")?;
1710
1711 assert_eq!(db.last_insert_rowid(), 1);
1712
1713 let mut stmt = db.prepare("INSERT INTO foo DEFAULT VALUES")?;
1714 for _ in 0i32..9 {
1715 stmt.execute([])?;
1716 }
1717 assert_eq!(db.last_insert_rowid(), 10);
1718 Ok(())
1719 }
1720
1721 #[test]
1722 fn test_is_autocommit() -> Result<()> {
1723 let db = Connection::open_in_memory()?;
1724 assert!(
1725 db.is_autocommit(),
1726 "autocommit expected to be active by default"
1727 );
1728 Ok(())
1729 }
1730
1731 #[test]
1732 fn test_is_busy() -> Result<()> {
1733 let db = Connection::open_in_memory()?;
1734 assert!(!db.is_busy());
1735 let mut stmt = db.prepare("PRAGMA schema_version")?;
1736 assert!(!db.is_busy());
1737 {
1738 let mut rows = stmt.query([])?;
1739 assert!(!db.is_busy());
1740 let row = rows.next()?;
1741 assert!(db.is_busy());
1742 assert!(row.is_some());
1743 }
1744 assert!(!db.is_busy());
1745 Ok(())
1746 }
1747
1748 #[test]
1749 fn test_statement_debugging() -> Result<()> {
1750 let db = Connection::open_in_memory()?;
1751 let query = "SELECT 12345";
1752 let stmt = db.prepare(query)?;
1753
1754 assert!(format!("{stmt:?}").contains(query));
1755 Ok(())
1756 }
1757
1758 #[test]
1759 fn test_notnull_constraint_error() -> Result<()> {
1760 fn check_extended_code(extended_code: c_int) {
1763 assert_eq!(extended_code, ffi::SQLITE_CONSTRAINT_NOTNULL);
1764 }
1765
1766 let db = Connection::open_in_memory()?;
1767 db.execute_batch("CREATE TABLE foo(x NOT NULL)")?;
1768
1769 let result = db.execute("INSERT INTO foo (x) VALUES (NULL)", []);
1770
1771 match result.unwrap_err() {
1772 Error::SqliteFailure(err, _) => {
1773 assert_eq!(err.code, ErrorCode::ConstraintViolation);
1774 check_extended_code(err.extended_code);
1775 }
1776 err => panic!("Unexpected error {err}"),
1777 }
1778 Ok(())
1779 }
1780
1781 #[test]
1782 fn test_version_string() {
1783 let n = version_number();
1784 let major = n / 1_000_000;
1785 let minor = (n % 1_000_000) / 1_000;
1786 let patch = n % 1_000;
1787
1788 assert!(version().contains(&format!("{major}.{minor}.{patch}")));
1789 }
1790
1791 #[test]
1792 #[cfg(feature = "functions")]
1793 fn test_interrupt() -> Result<()> {
1794 let db = Connection::open_in_memory()?;
1795
1796 let interrupt_handle = db.get_interrupt_handle();
1797
1798 db.create_scalar_function(
1799 "interrupt",
1800 0,
1801 functions::FunctionFlags::default(),
1802 move |_| {
1803 interrupt_handle.interrupt();
1804 Ok(0)
1805 },
1806 )?;
1807
1808 let mut stmt =
1809 db.prepare("SELECT interrupt() FROM (SELECT 1 UNION SELECT 2 UNION SELECT 3)")?;
1810
1811 let result: Result<Vec<i32>> = stmt.query([])?.map(|r| r.get(0)).collect();
1812
1813 assert_eq!(
1814 result.unwrap_err().sqlite_error_code(),
1815 Some(ErrorCode::OperationInterrupted)
1816 );
1817 Ok(())
1818 }
1819
1820 #[test]
1821 fn test_interrupt_close() {
1822 let db = checked_memory_handle();
1823 let handle = db.get_interrupt_handle();
1824 handle.interrupt();
1825 db.close().unwrap();
1826 handle.interrupt();
1827
1828 let db_guard = handle.db_lock.lock().unwrap();
1830 assert!(db_guard.is_null());
1831 }
1835
1836 #[test]
1837 fn test_get_raw() -> Result<()> {
1838 let db = Connection::open_in_memory()?;
1839 db.execute_batch("CREATE TABLE foo(i, x);")?;
1840 let vals = ["foobar", "1234", "qwerty"];
1841 let mut insert_stmt = db.prepare("INSERT INTO foo(i, x) VALUES(?1, ?2)")?;
1842 for (i, v) in vals.iter().enumerate() {
1843 let i_to_insert = i as i64;
1844 assert_eq!(insert_stmt.execute(params![i_to_insert, v])?, 1);
1845 }
1846
1847 let mut query = db.prepare("SELECT i, x FROM foo")?;
1848 let mut rows = query.query([])?;
1849
1850 while let Some(row) = rows.next()? {
1851 let i = row.get_ref(0)?.as_i64()?;
1852 let expect = vals[i as usize];
1853 let x = row.get_ref("x")?.as_str()?;
1854 assert_eq!(x, expect);
1855 }
1856
1857 let mut query = db.prepare("SELECT x FROM foo")?;
1858 let rows = query.query_map([], |row| {
1859 let x = row.get_ref(0)?.as_str()?; Ok(x[..].to_owned())
1861 })?;
1862
1863 for (i, row) in rows.enumerate() {
1864 assert_eq!(row?, vals[i]);
1865 }
1866 Ok(())
1867 }
1868
1869 #[test]
1870 fn test_from_handle() -> Result<()> {
1871 let db = Connection::open_in_memory()?;
1872 let handle = unsafe { db.handle() };
1873 {
1874 let db = unsafe { Connection::from_handle(handle) }?;
1875 db.execute_batch("PRAGMA VACUUM")?;
1876 }
1877 db.close().unwrap();
1878 Ok(())
1879 }
1880
1881 #[test]
1882 fn test_from_handle_owned() -> Result<()> {
1883 let mut handle: *mut ffi::sqlite3 = std::ptr::null_mut();
1884 let r = unsafe { ffi::sqlite3_open(":memory:\0".as_ptr() as *const c_char, &mut handle) };
1885 assert_eq!(r, ffi::SQLITE_OK);
1886 let db = unsafe { Connection::from_handle_owned(handle) }?;
1887 db.execute_batch("PRAGMA VACUUM")?;
1888 Ok(())
1889 }
1890
1891 mod query_and_then_tests {
1892
1893 use super::*;
1894
1895 #[derive(Debug)]
1896 enum CustomError {
1897 SomeError,
1898 Sqlite(Error),
1899 }
1900
1901 impl fmt::Display for CustomError {
1902 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1903 match *self {
1904 CustomError::SomeError => write!(f, "my custom error"),
1905 CustomError::Sqlite(ref se) => write!(f, "my custom error: {se}"),
1906 }
1907 }
1908 }
1909
1910 impl StdError for CustomError {
1911 fn description(&self) -> &str {
1912 "my custom error"
1913 }
1914
1915 fn cause(&self) -> Option<&dyn StdError> {
1916 match *self {
1917 CustomError::SomeError => None,
1918 CustomError::Sqlite(ref se) => Some(se),
1919 }
1920 }
1921 }
1922
1923 impl From<Error> for CustomError {
1924 fn from(se: Error) -> CustomError {
1925 CustomError::Sqlite(se)
1926 }
1927 }
1928
1929 type CustomResult<T> = Result<T, CustomError>;
1930
1931 #[test]
1932 fn test_query_and_then() -> Result<()> {
1933 let db = Connection::open_in_memory()?;
1934 let sql = "BEGIN;
1935 CREATE TABLE foo(x INTEGER, y TEXT);
1936 INSERT INTO foo VALUES(4, \"hello\");
1937 INSERT INTO foo VALUES(3, \", \");
1938 INSERT INTO foo VALUES(2, \"world\");
1939 INSERT INTO foo VALUES(1, \"!\");
1940 END;";
1941 db.execute_batch(sql)?;
1942
1943 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1944 let results: Result<Vec<String>> =
1945 query.query_and_then([], |row| row.get(1))?.collect();
1946
1947 assert_eq!(results?.concat(), "hello, world!");
1948 Ok(())
1949 }
1950
1951 #[test]
1952 fn test_query_and_then_fails() -> Result<()> {
1953 let db = Connection::open_in_memory()?;
1954 let sql = "BEGIN;
1955 CREATE TABLE foo(x INTEGER, y TEXT);
1956 INSERT INTO foo VALUES(4, \"hello\");
1957 INSERT INTO foo VALUES(3, \", \");
1958 INSERT INTO foo VALUES(2, \"world\");
1959 INSERT INTO foo VALUES(1, \"!\");
1960 END;";
1961 db.execute_batch(sql)?;
1962
1963 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1964 let bad_type: Result<Vec<f64>> = query.query_and_then([], |row| row.get(1))?.collect();
1965
1966 match bad_type.unwrap_err() {
1967 Error::InvalidColumnType(..) => (),
1968 err => panic!("Unexpected error {err}"),
1969 }
1970
1971 let bad_idx: Result<Vec<String>> =
1972 query.query_and_then([], |row| row.get(3))?.collect();
1973
1974 match bad_idx.unwrap_err() {
1975 Error::InvalidColumnIndex(_) => (),
1976 err => panic!("Unexpected error {err}"),
1977 }
1978 Ok(())
1979 }
1980
1981 #[test]
1982 fn test_query_and_then_custom_error() -> CustomResult<()> {
1983 let db = Connection::open_in_memory()?;
1984 let sql = "BEGIN;
1985 CREATE TABLE foo(x INTEGER, y TEXT);
1986 INSERT INTO foo VALUES(4, \"hello\");
1987 INSERT INTO foo VALUES(3, \", \");
1988 INSERT INTO foo VALUES(2, \"world\");
1989 INSERT INTO foo VALUES(1, \"!\");
1990 END;";
1991 db.execute_batch(sql)?;
1992
1993 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1994 let results: CustomResult<Vec<String>> = query
1995 .query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite))?
1996 .collect();
1997
1998 assert_eq!(results?.concat(), "hello, world!");
1999 Ok(())
2000 }
2001
2002 #[test]
2003 fn test_query_and_then_custom_error_fails() -> Result<()> {
2004 let db = Connection::open_in_memory()?;
2005 let sql = "BEGIN;
2006 CREATE TABLE foo(x INTEGER, y TEXT);
2007 INSERT INTO foo VALUES(4, \"hello\");
2008 INSERT INTO foo VALUES(3, \", \");
2009 INSERT INTO foo VALUES(2, \"world\");
2010 INSERT INTO foo VALUES(1, \"!\");
2011 END;";
2012 db.execute_batch(sql)?;
2013
2014 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
2015 let bad_type: CustomResult<Vec<f64>> = query
2016 .query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite))?
2017 .collect();
2018
2019 match bad_type.unwrap_err() {
2020 CustomError::Sqlite(Error::InvalidColumnType(..)) => (),
2021 err => panic!("Unexpected error {err}"),
2022 }
2023
2024 let bad_idx: CustomResult<Vec<String>> = query
2025 .query_and_then([], |row| row.get(3).map_err(CustomError::Sqlite))?
2026 .collect();
2027
2028 match bad_idx.unwrap_err() {
2029 CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
2030 err => panic!("Unexpected error {err}"),
2031 }
2032
2033 let non_sqlite_err: CustomResult<Vec<String>> = query
2034 .query_and_then([], |_| Err(CustomError::SomeError))?
2035 .collect();
2036
2037 match non_sqlite_err.unwrap_err() {
2038 CustomError::SomeError => (),
2039 err => panic!("Unexpected error {err}"),
2040 }
2041 Ok(())
2042 }
2043
2044 #[test]
2045 fn test_query_row_and_then_custom_error() -> CustomResult<()> {
2046 let db = Connection::open_in_memory()?;
2047 let sql = "BEGIN;
2048 CREATE TABLE foo(x INTEGER, y TEXT);
2049 INSERT INTO foo VALUES(4, \"hello\");
2050 END;";
2051 db.execute_batch(sql)?;
2052
2053 let query = "SELECT x, y FROM foo ORDER BY x DESC";
2054 let results: CustomResult<String> =
2055 db.query_row_and_then(query, [], |row| row.get(1).map_err(CustomError::Sqlite));
2056
2057 assert_eq!(results?, "hello");
2058 Ok(())
2059 }
2060
2061 #[test]
2062 fn test_query_row_and_then_custom_error_fails() -> Result<()> {
2063 let db = Connection::open_in_memory()?;
2064 let sql = "BEGIN;
2065 CREATE TABLE foo(x INTEGER, y TEXT);
2066 INSERT INTO foo VALUES(4, \"hello\");
2067 END;";
2068 db.execute_batch(sql)?;
2069
2070 let query = "SELECT x, y FROM foo ORDER BY x DESC";
2071 let bad_type: CustomResult<f64> =
2072 db.query_row_and_then(query, [], |row| row.get(1).map_err(CustomError::Sqlite));
2073
2074 match bad_type.unwrap_err() {
2075 CustomError::Sqlite(Error::InvalidColumnType(..)) => (),
2076 err => panic!("Unexpected error {err}"),
2077 }
2078
2079 let bad_idx: CustomResult<String> =
2080 db.query_row_and_then(query, [], |row| row.get(3).map_err(CustomError::Sqlite));
2081
2082 match bad_idx.unwrap_err() {
2083 CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
2084 err => panic!("Unexpected error {err}"),
2085 }
2086
2087 let non_sqlite_err: CustomResult<String> =
2088 db.query_row_and_then(query, [], |_| Err(CustomError::SomeError));
2089
2090 match non_sqlite_err.unwrap_err() {
2091 CustomError::SomeError => (),
2092 err => panic!("Unexpected error {err}"),
2093 }
2094 Ok(())
2095 }
2096 }
2097
2098 #[test]
2099 fn test_dynamic() -> Result<()> {
2100 let db = Connection::open_in_memory()?;
2101 let sql = "BEGIN;
2102 CREATE TABLE foo(x INTEGER, y TEXT);
2103 INSERT INTO foo VALUES(4, \"hello\");
2104 END;";
2105 db.execute_batch(sql)?;
2106
2107 db.query_row("SELECT * FROM foo", [], |r| {
2108 assert_eq!(2, r.as_ref().column_count());
2109 Ok(())
2110 })
2111 }
2112 #[test]
2113 fn test_dyn_box() -> Result<()> {
2114 let db = Connection::open_in_memory()?;
2115 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
2116 let b: Box<dyn ToSql> = Box::new(5);
2117 db.execute("INSERT INTO foo VALUES(?1)", [b])?;
2118 db.query_row("SELECT x FROM foo", [], |r| {
2119 assert_eq!(5, r.get_unwrap::<_, i32>(0));
2120 Ok(())
2121 })
2122 }
2123
2124 #[test]
2125 fn test_params() -> Result<()> {
2126 let db = Connection::open_in_memory()?;
2127 db.query_row(
2128 "SELECT
2129 ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10,
2130 ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19, ?20,
2131 ?21, ?22, ?23, ?24, ?25, ?26, ?27, ?28, ?29, ?30,
2132 ?31, ?32, ?33, ?34;",
2133 params![
2134 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,
2135 1, 1, 1, 1, 1, 1,
2136 ],
2137 |r| {
2138 assert_eq!(1, r.get_unwrap::<_, i32>(0));
2139 Ok(())
2140 },
2141 )
2142 }
2143
2144 #[test]
2145 #[cfg(not(feature = "extra_check"))]
2146 fn test_alter_table() -> Result<()> {
2147 let db = Connection::open_in_memory()?;
2148 db.execute_batch("CREATE TABLE x(t);")?;
2149 db.execute("ALTER TABLE x RENAME TO y;", [])?;
2151 Ok(())
2152 }
2153
2154 #[test]
2155 fn test_batch() -> Result<()> {
2156 let db = Connection::open_in_memory()?;
2157 let sql = r"
2158 CREATE TABLE tbl1 (col);
2159 CREATE TABLE tbl2 (col);
2160 ";
2161 let batch = Batch::new(&db, sql);
2162 for stmt in batch {
2163 let mut stmt = stmt?;
2164 stmt.execute([])?;
2165 }
2166 Ok(())
2167 }
2168
2169 #[test]
2170 #[cfg(feature = "modern_sqlite")]
2171 fn test_returning() -> Result<()> {
2172 let db = Connection::open_in_memory()?;
2173 db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)")?;
2174 let row_id = db.one_column::<i64>("INSERT INTO foo DEFAULT VALUES RETURNING ROWID")?;
2175 assert_eq!(row_id, 1);
2176 Ok(())
2177 }
2178
2179 #[test]
2180 fn test_cache_flush() -> Result<()> {
2181 let db = Connection::open_in_memory()?;
2182 db.cache_flush()
2183 }
2184
2185 #[test]
2186 fn db_readonly() -> Result<()> {
2187 let db = Connection::open_in_memory()?;
2188 assert!(!db.is_readonly(MAIN_DB)?);
2189 Ok(())
2190 }
2191
2192 #[test]
2193 #[cfg(feature = "rusqlite-macros")]
2194 fn prepare_and_bind() -> Result<()> {
2195 let db = Connection::open_in_memory()?;
2196 let name = "Lisa";
2197 let age = 8;
2198 let mut stmt = prepare_and_bind!(db, "SELECT $name, $age;");
2199 let (v1, v2) = stmt
2200 .raw_query()
2201 .next()
2202 .and_then(|o| o.ok_or(Error::QueryReturnedNoRows))
2203 .and_then(|r| Ok((r.get::<_, String>(0)?, r.get::<_, i64>(1)?)))?;
2204 assert_eq!((v1.as_str(), v2), (name, age));
2205 Ok(())
2206 }
2207}