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::{Arc, Mutex};
69
70use crate::cache::StatementCache;
71use crate::inner_connection::InnerConnection;
72use crate::raw_statement::RawStatement;
73use crate::types::ValueRef;
74
75pub use crate::cache::CachedStatement;
76#[cfg(feature = "column_decltype")]
77pub use crate::column::Column;
78pub use crate::error::{to_sqlite_error, Error};
79pub use crate::ffi::ErrorCode;
80#[cfg(feature = "load_extension")]
81pub use crate::load_extension_guard::LoadExtensionGuard;
82pub use crate::params::{params_from_iter, Params, ParamsFromIter};
83pub use crate::row::{AndThenRows, Map, MappedRows, Row, RowIndex, Rows};
84pub use crate::statement::{Statement, StatementStatus};
85#[cfg(feature = "modern_sqlite")]
86pub use crate::transaction::TransactionState;
87pub use crate::transaction::{DropBehavior, Savepoint, Transaction, TransactionBehavior};
88pub use crate::types::ToSql;
89pub use crate::version::*;
90#[cfg(feature = "rusqlite-macros")]
91#[doc(hidden)]
92pub use rusqlite_macros::__bind;
93
94mod error;
95
96#[cfg(not(feature = "loadable_extension"))]
97pub mod auto_extension;
98#[cfg(feature = "backup")]
99#[cfg_attr(docsrs, doc(cfg(feature = "backup")))]
100pub mod backup;
101#[cfg(feature = "blob")]
102#[cfg_attr(docsrs, doc(cfg(feature = "blob")))]
103pub mod blob;
104mod busy;
105mod cache;
106#[cfg(feature = "collation")]
107#[cfg_attr(docsrs, doc(cfg(feature = "collation")))]
108mod collation;
109mod column;
110pub mod config;
111#[cfg(any(feature = "functions", feature = "vtab"))]
112mod context;
113#[cfg(feature = "functions")]
114#[cfg_attr(docsrs, doc(cfg(feature = "functions")))]
115pub mod functions;
116#[cfg(feature = "hooks")]
117#[cfg_attr(docsrs, doc(cfg(feature = "hooks")))]
118pub mod hooks;
119mod inner_connection;
120#[cfg(feature = "limits")]
121#[cfg_attr(docsrs, doc(cfg(feature = "limits")))]
122pub mod limits;
123#[cfg(feature = "load_extension")]
124mod load_extension_guard;
125mod params;
126mod pragma;
127mod raw_statement;
128mod row;
129#[cfg(feature = "serialize")]
130#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
131pub mod serialize;
132#[cfg(feature = "session")]
133#[cfg_attr(docsrs, doc(cfg(feature = "session")))]
134pub mod session;
135mod statement;
136#[cfg(feature = "trace")]
137#[cfg_attr(docsrs, doc(cfg(feature = "trace")))]
138pub mod trace;
139mod transaction;
140pub mod types;
141#[cfg(feature = "unlock_notify")]
142mod unlock_notify;
143mod version;
144#[cfg(feature = "vtab")]
145#[cfg_attr(docsrs, doc(cfg(feature = "vtab")))]
146pub mod vtab;
147
148pub(crate) mod util;
149pub(crate) use util::SmallCString;
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#[cfg_attr(docsrs, doc(cfg(feature = "rusqlite-macros")))]
245#[macro_export]
246macro_rules! prepare_and_bind {
247 ($conn:expr, $sql:literal) => {{
248 let mut stmt = $conn.prepare($sql)?;
249 $crate::__bind!(stmt $sql);
250 stmt
251 }};
252}
253
254#[cfg(feature = "rusqlite-macros")]
260#[cfg_attr(docsrs, doc(cfg(feature = "rusqlite-macros")))]
261#[macro_export]
262macro_rules! prepare_cached_and_bind {
263 ($conn:expr, $sql:literal) => {{
264 let mut stmt = $conn.prepare_cached($sql)?;
265 $crate::__bind!(stmt $sql);
266 stmt
267 }};
268}
269
270pub type Result<T, E = Error> = result::Result<T, E>;
272
273pub trait OptionalExtension<T> {
275 fn optional(self) -> Result<Option<T>>;
281}
282
283impl<T> OptionalExtension<T> for Result<T> {
284 fn optional(self) -> Result<Option<T>> {
285 match self {
286 Ok(value) => Ok(Some(value)),
287 Err(Error::QueryReturnedNoRows) => Ok(None),
288 Err(e) => Err(e),
289 }
290 }
291}
292
293unsafe fn errmsg_to_string(errmsg: *const c_char) -> String {
294 CStr::from_ptr(errmsg).to_string_lossy().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"), 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 transaction_behavior: TransactionBehavior,
381}
382
383unsafe impl Send for Connection {}
384
385impl Drop for Connection {
386 #[inline]
387 fn drop(&mut self) {
388 self.flush_prepared_statement_cache();
389 }
390}
391
392impl Connection {
393 #[inline]
446 pub fn open<P: AsRef<Path>>(path: P) -> Result<Connection> {
447 let flags = OpenFlags::default();
448 Connection::open_with_flags(path, flags)
449 }
450
451 #[inline]
457 pub fn open_in_memory() -> Result<Connection> {
458 let flags = OpenFlags::default();
459 Connection::open_in_memory_with_flags(flags)
460 }
461
462 #[inline]
472 pub fn open_with_flags<P: AsRef<Path>>(path: P, flags: OpenFlags) -> Result<Connection> {
473 let c_path = path_to_cstring(path.as_ref())?;
474 InnerConnection::open_with_flags(&c_path, flags, None).map(|db| Connection {
475 db: RefCell::new(db),
476 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
477 transaction_behavior: TransactionBehavior::Deferred,
478 })
479 }
480
481 #[inline]
492 pub fn open_with_flags_and_vfs<P: AsRef<Path>>(
493 path: P,
494 flags: OpenFlags,
495 vfs: &str,
496 ) -> Result<Connection> {
497 let c_path = path_to_cstring(path.as_ref())?;
498 let c_vfs = str_to_cstring(vfs)?;
499 InnerConnection::open_with_flags(&c_path, flags, Some(&c_vfs)).map(|db| Connection {
500 db: RefCell::new(db),
501 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
502 transaction_behavior: TransactionBehavior::Deferred,
503 })
504 }
505
506 #[inline]
515 pub fn open_in_memory_with_flags(flags: OpenFlags) -> Result<Connection> {
516 Connection::open_with_flags(":memory:", flags)
517 }
518
519 #[inline]
530 pub fn open_in_memory_with_flags_and_vfs(flags: OpenFlags, vfs: &str) -> Result<Connection> {
531 Connection::open_with_flags_and_vfs(":memory:", flags, vfs)
532 }
533
534 pub fn execute_batch(&self, sql: &str) -> Result<()> {
556 let mut sql = sql;
557 while !sql.is_empty() {
558 let stmt = self.prepare(sql)?;
559 if !stmt.stmt.is_null() && stmt.step()? && cfg!(feature = "extra_check") {
560 return Err(Error::ExecuteReturnedResults);
562 }
563 let tail = stmt.stmt.tail();
564 if tail == 0 || tail >= sql.len() {
565 break;
566 }
567 sql = &sql[tail..];
568 }
569 Ok(())
570 }
571
572 #[inline]
623 pub fn execute<P: Params>(&self, sql: &str, params: P) -> Result<usize> {
624 self.prepare(sql)
625 .and_then(|mut stmt| stmt.check_no_tail().and_then(|()| stmt.execute(params)))
626 }
627
628 #[inline]
636 pub fn path(&self) -> Option<&str> {
637 unsafe {
638 let db = self.handle();
639 let db_name = DatabaseName::Main.as_cstring().unwrap();
640 let db_filename = ffi::sqlite3_db_filename(db, db_name.as_ptr());
641 if db_filename.is_null() {
642 None
643 } else {
644 CStr::from_ptr(db_filename).to_str().ok()
645 }
646 }
647 }
648
649 #[inline]
654 #[cfg(feature = "release_memory")]
655 pub fn release_memory(&self) -> Result<()> {
656 self.db.borrow_mut().release_memory()
657 }
658
659 #[inline]
664 pub fn last_insert_rowid(&self) -> i64 {
665 self.db.borrow_mut().last_insert_rowid()
666 }
667
668 #[inline]
696 pub fn query_row<T, P, F>(&self, sql: &str, params: P, f: F) -> Result<T>
697 where
698 P: Params,
699 F: FnOnce(&Row<'_>) -> Result<T>,
700 {
701 let mut stmt = self.prepare(sql)?;
702 stmt.check_no_tail()?;
703 stmt.query_row(params, f)
704 }
705
706 #[cfg(test)]
708 pub(crate) fn one_column<T: types::FromSql>(&self, sql: &str) -> Result<T> {
709 self.query_row(sql, [], |r| r.get(0))
710 }
711
712 #[inline]
738 pub fn query_row_and_then<T, E, P, F>(&self, sql: &str, params: P, f: F) -> Result<T, E>
739 where
740 P: Params,
741 F: FnOnce(&Row<'_>) -> Result<T, E>,
742 E: From<Error>,
743 {
744 let mut stmt = self.prepare(sql)?;
745 stmt.check_no_tail()?;
746 let mut rows = stmt.query(params)?;
747
748 rows.get_expected_row().map_err(E::from).and_then(f)
749 }
750
751 #[inline]
770 pub fn prepare(&self, sql: &str) -> Result<Statement<'_>> {
771 self.prepare_with_flags(sql, PrepFlags::default())
772 }
773
774 #[inline]
781 pub fn prepare_with_flags(&self, sql: &str, flags: PrepFlags) -> Result<Statement<'_>> {
782 self.db.borrow_mut().prepare(self, sql, flags)
783 }
784
785 #[inline]
795 pub fn close(self) -> Result<(), (Connection, Error)> {
796 self.flush_prepared_statement_cache();
797 let r = self.db.borrow_mut().close();
798 r.map_err(move |err| (self, err))
799 }
800
801 #[cfg(feature = "load_extension")]
854 #[cfg_attr(docsrs, doc(cfg(feature = "load_extension")))]
855 #[inline]
856 pub unsafe fn load_extension_enable(&self) -> Result<()> {
857 self.db.borrow_mut().enable_load_extension(1)
858 }
859
860 #[cfg(feature = "load_extension")]
868 #[cfg_attr(docsrs, doc(cfg(feature = "load_extension")))]
869 #[inline]
870 pub fn load_extension_disable(&self) -> Result<()> {
871 unsafe { self.db.borrow_mut().enable_load_extension(0) }
873 }
874
875 #[cfg(feature = "load_extension")]
911 #[cfg_attr(docsrs, doc(cfg(feature = "load_extension")))]
912 #[inline]
913 pub unsafe fn load_extension<P: AsRef<Path>>(
914 &self,
915 dylib_path: P,
916 entry_point: Option<&str>,
917 ) -> Result<()> {
918 self.db
919 .borrow_mut()
920 .load_extension(dylib_path.as_ref(), entry_point)
921 }
922
923 #[inline]
937 pub unsafe fn handle(&self) -> *mut ffi::sqlite3 {
938 self.db.borrow().db()
939 }
940
941 #[inline]
950 pub unsafe fn from_handle(db: *mut ffi::sqlite3) -> Result<Connection> {
951 let db = InnerConnection::new(db, false);
952 Ok(Connection {
953 db: RefCell::new(db),
954 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
955 transaction_behavior: TransactionBehavior::Deferred,
956 })
957 }
958
959 #[cfg(feature = "loadable_extension")]
965 #[cfg_attr(docsrs, doc(cfg(feature = "loadable_extension")))]
966 pub unsafe fn extension_init2(
967 db: *mut ffi::sqlite3,
968 pz_err_msg: *mut *mut c_char,
969 p_api: *mut ffi::sqlite3_api_routines,
970 init: fn(Connection) -> Result<bool>,
971 ) -> c_int {
972 if p_api.is_null() {
973 return ffi::SQLITE_ERROR;
974 }
975 match ffi::rusqlite_extension_init2(p_api)
976 .map_err(Error::from)
977 .and(Connection::from_handle(db))
978 .and_then(init)
979 {
980 Err(err) => to_sqlite_error(&err, pz_err_msg),
981 Ok(true) => ffi::SQLITE_OK_LOAD_PERMANENTLY,
982 _ => ffi::SQLITE_OK,
983 }
984 }
985
986 #[inline]
999 pub unsafe fn from_handle_owned(db: *mut ffi::sqlite3) -> Result<Connection> {
1000 let db = InnerConnection::new(db, true);
1001 Ok(Connection {
1002 db: RefCell::new(db),
1003 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
1004 transaction_behavior: TransactionBehavior::Deferred,
1005 })
1006 }
1007
1008 #[inline]
1011 pub fn get_interrupt_handle(&self) -> InterruptHandle {
1012 self.db.borrow().get_interrupt_handle()
1013 }
1014
1015 #[inline]
1016 fn decode_result(&self, code: c_int) -> Result<()> {
1017 self.db.borrow().decode_result(code)
1018 }
1019
1020 #[inline]
1026 pub fn changes(&self) -> u64 {
1027 self.db.borrow().changes()
1028 }
1029
1030 #[inline]
1036 pub fn total_changes(&self) -> u64 {
1037 self.db.borrow().total_changes()
1038 }
1039
1040 #[inline]
1043 pub fn is_autocommit(&self) -> bool {
1044 self.db.borrow().is_autocommit()
1045 }
1046
1047 #[inline]
1049 pub fn is_busy(&self) -> bool {
1050 self.db.borrow().is_busy()
1051 }
1052
1053 pub fn cache_flush(&self) -> Result<()> {
1055 self.db.borrow_mut().cache_flush()
1056 }
1057
1058 pub fn is_readonly(&self, db_name: DatabaseName<'_>) -> Result<bool> {
1060 self.db.borrow().db_readonly(db_name)
1061 }
1062
1063 #[cfg(feature = "modern_sqlite")] #[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
1070 pub fn db_name(&self, index: usize) -> Result<String> {
1071 unsafe {
1072 let db = self.handle();
1073 let name = ffi::sqlite3_db_name(db, index as c_int);
1074 if name.is_null() {
1075 Err(Error::InvalidDatabaseIndex(index))
1076 } else {
1077 Ok(CStr::from_ptr(name).to_str()?.to_owned())
1078 }
1079 }
1080 }
1081
1082 #[cfg(feature = "modern_sqlite")] #[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
1085 pub fn is_interrupted(&self) -> bool {
1086 self.db.borrow().is_interrupted()
1087 }
1088}
1089
1090impl fmt::Debug for Connection {
1091 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1092 f.debug_struct("Connection")
1093 .field("path", &self.path())
1094 .finish()
1095 }
1096}
1097
1098#[derive(Debug)]
1116pub struct Batch<'conn, 'sql> {
1117 conn: &'conn Connection,
1118 sql: &'sql str,
1119 tail: usize,
1120}
1121
1122impl<'conn, 'sql> Batch<'conn, 'sql> {
1123 pub fn new(conn: &'conn Connection, sql: &'sql str) -> Batch<'conn, 'sql> {
1125 Batch { conn, sql, tail: 0 }
1126 }
1127
1128 #[allow(clippy::should_implement_trait)] pub fn next(&mut self) -> Result<Option<Statement<'conn>>> {
1133 while self.tail < self.sql.len() {
1134 let sql = &self.sql[self.tail..];
1135 let next = self.conn.prepare(sql)?;
1136 let tail = next.stmt.tail();
1137 if tail == 0 {
1138 self.tail = self.sql.len();
1139 } else {
1140 self.tail += tail;
1141 }
1142 if next.stmt.is_null() {
1143 continue;
1144 }
1145 return Ok(Some(next));
1146 }
1147 Ok(None)
1148 }
1149}
1150
1151impl<'conn> Iterator for Batch<'conn, '_> {
1152 type Item = Result<Statement<'conn>>;
1153
1154 fn next(&mut self) -> Option<Result<Statement<'conn>>> {
1155 self.next().transpose()
1156 }
1157}
1158
1159bitflags::bitflags! {
1160 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1167 #[repr(C)]
1168 pub struct OpenFlags: ::std::os::raw::c_int {
1169 const SQLITE_OPEN_READ_ONLY = ffi::SQLITE_OPEN_READONLY;
1172 const SQLITE_OPEN_READ_WRITE = ffi::SQLITE_OPEN_READWRITE;
1176 const SQLITE_OPEN_CREATE = ffi::SQLITE_OPEN_CREATE;
1178 const SQLITE_OPEN_URI = ffi::SQLITE_OPEN_URI;
1180 const SQLITE_OPEN_MEMORY = ffi::SQLITE_OPEN_MEMORY;
1182 const SQLITE_OPEN_NO_MUTEX = ffi::SQLITE_OPEN_NOMUTEX;
1191 const SQLITE_OPEN_FULL_MUTEX = ffi::SQLITE_OPEN_FULLMUTEX;
1215 const SQLITE_OPEN_SHARED_CACHE = 0x0002_0000;
1222 const SQLITE_OPEN_PRIVATE_CACHE = 0x0004_0000;
1224 const SQLITE_OPEN_NOFOLLOW = 0x0100_0000;
1226 const SQLITE_OPEN_EXRESCODE = 0x0200_0000;
1228 }
1229}
1230
1231impl Default for OpenFlags {
1232 #[inline]
1233 fn default() -> OpenFlags {
1234 OpenFlags::SQLITE_OPEN_READ_WRITE
1237 | OpenFlags::SQLITE_OPEN_CREATE
1238 | OpenFlags::SQLITE_OPEN_NO_MUTEX
1239 | OpenFlags::SQLITE_OPEN_URI
1240 }
1241}
1242
1243bitflags::bitflags! {
1244 #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
1247 #[repr(C)]
1248 pub struct PrepFlags: ::std::os::raw::c_uint {
1249 const SQLITE_PREPARE_PERSISTENT = 0x01;
1251 const SQLITE_PREPARE_NO_VTAB = 0x04;
1253 }
1254}
1255
1256pub struct InterruptHandle {
1258 db_lock: Arc<Mutex<*mut ffi::sqlite3>>,
1259}
1260
1261unsafe impl Send for InterruptHandle {}
1262unsafe impl Sync for InterruptHandle {}
1263
1264impl InterruptHandle {
1265 pub fn interrupt(&self) {
1268 let db_handle = self.db_lock.lock().unwrap();
1269 if !db_handle.is_null() {
1270 unsafe { ffi::sqlite3_interrupt(*db_handle) }
1271 }
1272 }
1273}
1274
1275#[cfg(doctest)]
1276doc_comment::doctest!("../README.md");
1277
1278#[cfg(test)]
1279mod test {
1280 use super::*;
1281 use fallible_iterator::FallibleIterator;
1282 use std::error::Error as StdError;
1283 use std::fmt;
1284
1285 #[allow(
1289 dead_code,
1290 unconditional_recursion,
1291 clippy::extra_unused_type_parameters
1292 )]
1293 fn ensure_send<T: Send>() {
1294 ensure_send::<Connection>();
1295 ensure_send::<InterruptHandle>();
1296 }
1297
1298 #[allow(
1299 dead_code,
1300 unconditional_recursion,
1301 clippy::extra_unused_type_parameters
1302 )]
1303 fn ensure_sync<T: Sync>() {
1304 ensure_sync::<InterruptHandle>();
1305 }
1306
1307 fn checked_memory_handle() -> Connection {
1308 Connection::open_in_memory().unwrap()
1309 }
1310
1311 #[test]
1312 fn test_concurrent_transactions_busy_commit() -> Result<()> {
1313 use std::time::Duration;
1314 let tmp = tempfile::tempdir().unwrap();
1315 let path = tmp.path().join("transactions.db3");
1316
1317 Connection::open(&path)?.execute_batch(
1318 "
1319 BEGIN; CREATE TABLE foo(x INTEGER);
1320 INSERT INTO foo VALUES(42); END;",
1321 )?;
1322
1323 let mut db1 = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_WRITE)?;
1324 let mut db2 = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_ONLY)?;
1325
1326 db1.busy_timeout(Duration::from_millis(0))?;
1327 db2.busy_timeout(Duration::from_millis(0))?;
1328
1329 {
1330 let tx1 = db1.transaction()?;
1331 let tx2 = db2.transaction()?;
1332
1333 tx1.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))?;
1335 tx2.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))?;
1336
1337 tx1.execute("INSERT INTO foo VALUES(?1)", [1])?;
1338 let _ = tx2.execute("INSERT INTO foo VALUES(?1)", [2]);
1339
1340 let _ = tx1.commit();
1341 let _ = tx2.commit();
1342 }
1343
1344 let _ = db1
1345 .transaction()
1346 .expect("commit should have closed transaction");
1347 let _ = db2
1348 .transaction()
1349 .expect("commit should have closed transaction");
1350 Ok(())
1351 }
1352
1353 #[test]
1354 fn test_persistence() -> Result<()> {
1355 let temp_dir = tempfile::tempdir().unwrap();
1356 let path = temp_dir.path().join("test.db3");
1357
1358 {
1359 let db = Connection::open(&path)?;
1360 let sql = "BEGIN;
1361 CREATE TABLE foo(x INTEGER);
1362 INSERT INTO foo VALUES(42);
1363 END;";
1364 db.execute_batch(sql)?;
1365 }
1366
1367 let path_string = path.to_str().unwrap();
1368 let db = Connection::open(path_string)?;
1369 let the_answer: i64 = db.one_column("SELECT x FROM foo")?;
1370
1371 assert_eq!(42i64, the_answer);
1372 Ok(())
1373 }
1374
1375 #[test]
1376 fn test_open() {
1377 Connection::open_in_memory().unwrap();
1378
1379 let db = checked_memory_handle();
1380 db.close().unwrap();
1381 }
1382
1383 #[test]
1384 fn test_path() -> Result<()> {
1385 let tmp = tempfile::tempdir().unwrap();
1386 let db = Connection::open("")?;
1387 assert_eq!(Some(""), db.path());
1388 let db = Connection::open_in_memory()?;
1389 assert_eq!(Some(""), db.path());
1390 let db = Connection::open("file:dummy.db?mode=memory&cache=shared")?;
1391 assert_eq!(Some(""), db.path());
1392 let path = tmp.path().join("file.db");
1393 let db = Connection::open(path)?;
1394 assert!(db.path().map(|p| p.ends_with("file.db")).unwrap_or(false));
1395 Ok(())
1396 }
1397
1398 #[test]
1399 fn test_open_failure() {
1400 let filename = "no_such_file.db";
1401 let result = Connection::open_with_flags(filename, OpenFlags::SQLITE_OPEN_READ_ONLY);
1402 let err = result.unwrap_err();
1403 if let Error::SqliteFailure(e, Some(msg)) = err {
1404 assert_eq!(ErrorCode::CannotOpen, e.code);
1405 assert_eq!(ffi::SQLITE_CANTOPEN, e.extended_code);
1406 assert!(
1407 msg.contains(filename),
1408 "error message '{msg}' does not contain '{filename}'"
1409 );
1410 } else {
1411 panic!("SqliteFailure expected");
1412 }
1413 }
1414
1415 #[cfg(unix)]
1416 #[test]
1417 fn test_invalid_unicode_file_names() -> Result<()> {
1418 use std::ffi::OsStr;
1419 use std::fs::File;
1420 use std::os::unix::ffi::OsStrExt;
1421 let temp_dir = tempfile::tempdir().unwrap();
1422
1423 let path = temp_dir.path();
1424 if File::create(path.join(OsStr::from_bytes(&[0xFE]))).is_err() {
1425 return Ok(());
1427 }
1428 let db_path = path.join(OsStr::from_bytes(&[0xFF]));
1429 {
1430 let db = Connection::open(&db_path)?;
1431 let sql = "BEGIN;
1432 CREATE TABLE foo(x INTEGER);
1433 INSERT INTO foo VALUES(42);
1434 END;";
1435 db.execute_batch(sql)?;
1436 }
1437
1438 let db = Connection::open(&db_path)?;
1439 let the_answer: i64 = db.one_column("SELECT x FROM foo")?;
1440
1441 assert_eq!(42i64, the_answer);
1442 Ok(())
1443 }
1444
1445 #[test]
1446 fn test_close_retry() -> Result<()> {
1447 let db = Connection::open_in_memory()?;
1448
1449 let raw_stmt = {
1453 use super::str_to_cstring;
1454 use std::os::raw::c_int;
1455 use std::ptr;
1456
1457 let raw_db = db.db.borrow_mut().db;
1458 let sql = "SELECT 1";
1459 let mut raw_stmt: *mut ffi::sqlite3_stmt = ptr::null_mut();
1460 let cstring = str_to_cstring(sql)?;
1461 let rc = unsafe {
1462 ffi::sqlite3_prepare_v2(
1463 raw_db,
1464 cstring.as_ptr(),
1465 (sql.len() + 1) as c_int,
1466 &mut raw_stmt,
1467 ptr::null_mut(),
1468 )
1469 };
1470 assert_eq!(rc, ffi::SQLITE_OK);
1471 raw_stmt
1472 };
1473
1474 let (db, _) = db.close().unwrap_err();
1477 let (db, _) = db.close().unwrap_err();
1478 let (db, _) = db.close().unwrap_err();
1479
1480 assert_eq!(ffi::SQLITE_OK, unsafe { ffi::sqlite3_finalize(raw_stmt) });
1482
1483 db.close().unwrap();
1484 Ok(())
1485 }
1486
1487 #[test]
1488 fn test_open_with_flags() {
1489 for bad_flags in &[
1490 OpenFlags::empty(),
1491 OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_READ_WRITE,
1492 OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_CREATE,
1493 ] {
1494 Connection::open_in_memory_with_flags(*bad_flags).unwrap_err();
1495 }
1496 }
1497
1498 #[test]
1499 fn test_execute_batch() -> Result<()> {
1500 let db = Connection::open_in_memory()?;
1501 let sql = "BEGIN;
1502 CREATE TABLE foo(x INTEGER);
1503 INSERT INTO foo VALUES(1);
1504 INSERT INTO foo VALUES(2);
1505 INSERT INTO foo VALUES(3);
1506 INSERT INTO foo VALUES(4);
1507 END;";
1508 db.execute_batch(sql)?;
1509
1510 db.execute_batch("UPDATE foo SET x = 3 WHERE x < 3")?;
1511
1512 db.execute_batch("INVALID SQL").unwrap_err();
1513 Ok(())
1514 }
1515
1516 #[test]
1517 fn test_execute() -> Result<()> {
1518 let db = Connection::open_in_memory()?;
1519 db.execute_batch("CREATE TABLE foo(x INTEGER)")?;
1520
1521 assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?1)", [1i32])?);
1522 assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?1)", [2i32])?);
1523
1524 assert_eq!(3i32, db.one_column::<i32>("SELECT SUM(x) FROM foo")?);
1525 Ok(())
1526 }
1527
1528 #[test]
1529 #[cfg(feature = "extra_check")]
1530 fn test_execute_select_with_no_row() {
1531 let db = checked_memory_handle();
1532 let err = db.execute("SELECT 1 WHERE 1 < ?1", [1i32]).unwrap_err();
1533 assert_eq!(
1534 err,
1535 Error::ExecuteReturnedResults,
1536 "Unexpected error: {err}"
1537 );
1538 }
1539
1540 #[test]
1541 fn test_execute_select_with_row() {
1542 let db = checked_memory_handle();
1543 let err = db.execute("SELECT 1", []).unwrap_err();
1544 assert_eq!(err, Error::ExecuteReturnedResults);
1545 }
1546
1547 #[test]
1548 #[cfg(feature = "extra_check")]
1549 fn test_execute_multiple() {
1550 let db = checked_memory_handle();
1551 let err = db
1552 .execute(
1553 "CREATE TABLE foo(x INTEGER); CREATE TABLE foo(x INTEGER)",
1554 [],
1555 )
1556 .unwrap_err();
1557 match err {
1558 Error::MultipleStatement => (),
1559 _ => panic!("Unexpected error: {err}"),
1560 }
1561 }
1562
1563 #[test]
1564 fn test_prepare_column_names() -> Result<()> {
1565 let db = Connection::open_in_memory()?;
1566 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1567
1568 let stmt = db.prepare("SELECT * FROM foo")?;
1569 assert_eq!(stmt.column_count(), 1);
1570 assert_eq!(stmt.column_names(), vec!["x"]);
1571
1572 let stmt = db.prepare("SELECT x AS a, x AS b FROM foo")?;
1573 assert_eq!(stmt.column_count(), 2);
1574 assert_eq!(stmt.column_names(), vec!["a", "b"]);
1575 Ok(())
1576 }
1577
1578 #[test]
1579 fn test_prepare_execute() -> Result<()> {
1580 let db = Connection::open_in_memory()?;
1581 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1582
1583 let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?1)")?;
1584 assert_eq!(insert_stmt.execute([1i32])?, 1);
1585 assert_eq!(insert_stmt.execute([2i32])?, 1);
1586 assert_eq!(insert_stmt.execute([3i32])?, 1);
1587
1588 assert_eq!(insert_stmt.execute(["hello"])?, 1);
1589 assert_eq!(insert_stmt.execute(["goodbye"])?, 1);
1590 assert_eq!(insert_stmt.execute([types::Null])?, 1);
1591
1592 let mut update_stmt = db.prepare("UPDATE foo SET x=?1 WHERE x<?2")?;
1593 assert_eq!(update_stmt.execute([3i32, 3i32])?, 2);
1594 assert_eq!(update_stmt.execute([3i32, 3i32])?, 0);
1595 assert_eq!(update_stmt.execute([8i32, 8i32])?, 3);
1596 Ok(())
1597 }
1598
1599 #[test]
1600 fn test_prepare_query() -> Result<()> {
1601 let db = Connection::open_in_memory()?;
1602 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1603
1604 let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?1)")?;
1605 assert_eq!(insert_stmt.execute([1i32])?, 1);
1606 assert_eq!(insert_stmt.execute([2i32])?, 1);
1607 assert_eq!(insert_stmt.execute([3i32])?, 1);
1608
1609 let mut query = db.prepare("SELECT x FROM foo WHERE x < ?1 ORDER BY x DESC")?;
1610 {
1611 let mut rows = query.query([4i32])?;
1612 let mut v = Vec::<i32>::new();
1613
1614 while let Some(row) = rows.next()? {
1615 v.push(row.get(0)?);
1616 }
1617
1618 assert_eq!(v, [3i32, 2, 1]);
1619 }
1620
1621 {
1622 let mut rows = query.query([3i32])?;
1623 let mut v = Vec::<i32>::new();
1624
1625 while let Some(row) = rows.next()? {
1626 v.push(row.get(0)?);
1627 }
1628
1629 assert_eq!(v, [2i32, 1]);
1630 }
1631 Ok(())
1632 }
1633
1634 #[test]
1635 fn test_query_map() -> Result<()> {
1636 let db = Connection::open_in_memory()?;
1637 let sql = "BEGIN;
1638 CREATE TABLE foo(x INTEGER, y TEXT);
1639 INSERT INTO foo VALUES(4, \"hello\");
1640 INSERT INTO foo VALUES(3, \", \");
1641 INSERT INTO foo VALUES(2, \"world\");
1642 INSERT INTO foo VALUES(1, \"!\");
1643 END;";
1644 db.execute_batch(sql)?;
1645
1646 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1647 let results: Result<Vec<String>> = query.query([])?.map(|row| row.get(1)).collect();
1648
1649 assert_eq!(results?.concat(), "hello, world!");
1650 Ok(())
1651 }
1652
1653 #[test]
1654 fn test_query_row() -> Result<()> {
1655 let db = Connection::open_in_memory()?;
1656 let sql = "BEGIN;
1657 CREATE TABLE foo(x INTEGER);
1658 INSERT INTO foo VALUES(1);
1659 INSERT INTO foo VALUES(2);
1660 INSERT INTO foo VALUES(3);
1661 INSERT INTO foo VALUES(4);
1662 END;";
1663 db.execute_batch(sql)?;
1664
1665 assert_eq!(10i64, db.one_column::<i64>("SELECT SUM(x) FROM foo")?);
1666
1667 let result: Result<i64> = db.one_column("SELECT x FROM foo WHERE x > 5");
1668 match result.unwrap_err() {
1669 Error::QueryReturnedNoRows => (),
1670 err => panic!("Unexpected error {err}"),
1671 }
1672
1673 let bad_query_result = db.query_row("NOT A PROPER QUERY; test123", [], |_| Ok(()));
1674
1675 bad_query_result.unwrap_err();
1676 Ok(())
1677 }
1678
1679 #[test]
1680 fn test_optional() -> Result<()> {
1681 let db = Connection::open_in_memory()?;
1682
1683 let result: Result<i64> = db.one_column("SELECT 1 WHERE 0 <> 0");
1684 let result = result.optional();
1685 match result? {
1686 None => (),
1687 _ => panic!("Unexpected result"),
1688 }
1689
1690 let result: Result<i64> = db.one_column("SELECT 1 WHERE 0 == 0");
1691 let result = result.optional();
1692 match result? {
1693 Some(1) => (),
1694 _ => panic!("Unexpected result"),
1695 }
1696
1697 let bad_query_result: Result<i64> = db.one_column("NOT A PROPER QUERY");
1698 let bad_query_result = bad_query_result.optional();
1699 bad_query_result.unwrap_err();
1700 Ok(())
1701 }
1702
1703 #[test]
1704 fn test_pragma_query_row() -> Result<()> {
1705 let db = Connection::open_in_memory()?;
1706 assert_eq!("memory", db.one_column::<String>("PRAGMA journal_mode")?);
1707 let mode = db.one_column::<String>("PRAGMA journal_mode=off")?;
1708 if cfg!(feature = "bundled") {
1709 assert_eq!(mode, "off");
1710 } else {
1711 assert!(mode == "memory" || mode == "off", "Got mode {mode:?}");
1723 }
1724
1725 Ok(())
1726 }
1727
1728 #[test]
1729 fn test_prepare_failures() -> Result<()> {
1730 let db = Connection::open_in_memory()?;
1731 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1732
1733 let err = db.prepare("SELECT * FROM does_not_exist").unwrap_err();
1734 assert!(format!("{err}").contains("does_not_exist"));
1735 Ok(())
1736 }
1737
1738 #[test]
1739 fn test_last_insert_rowid() -> Result<()> {
1740 let db = Connection::open_in_memory()?;
1741 db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)")?;
1742 db.execute_batch("INSERT INTO foo DEFAULT VALUES")?;
1743
1744 assert_eq!(db.last_insert_rowid(), 1);
1745
1746 let mut stmt = db.prepare("INSERT INTO foo DEFAULT VALUES")?;
1747 for _ in 0i32..9 {
1748 stmt.execute([])?;
1749 }
1750 assert_eq!(db.last_insert_rowid(), 10);
1751 Ok(())
1752 }
1753
1754 #[test]
1755 fn test_total_changes() -> Result<()> {
1756 let db = Connection::open_in_memory()?;
1757 let sql = "CREATE TABLE foo(x INTEGER PRIMARY KEY, value TEXT default '' NOT NULL,
1758 desc TEXT default '');
1759 CREATE VIEW foo_bar AS SELECT x, desc FROM foo WHERE value = 'bar';
1760 CREATE TRIGGER INSERT_FOOBAR
1761 INSTEAD OF INSERT
1762 ON foo_bar
1763 BEGIN
1764 INSERT INTO foo VALUES(new.x, 'bar', new.desc);
1765 END;";
1766 db.execute_batch(sql)?;
1767 let total_changes_before = db.total_changes();
1768 let changes = db
1769 .prepare("INSERT INTO foo_bar VALUES(null, 'baz');")?
1770 .execute([])?;
1771 let total_changes_after = db.total_changes();
1772 assert_eq!(changes, 0);
1773 assert_eq!(total_changes_after - total_changes_before, 1);
1774 Ok(())
1775 }
1776
1777 #[test]
1778 fn test_is_autocommit() -> Result<()> {
1779 let db = Connection::open_in_memory()?;
1780 assert!(
1781 db.is_autocommit(),
1782 "autocommit expected to be active by default"
1783 );
1784 Ok(())
1785 }
1786
1787 #[test]
1788 fn test_is_busy() -> Result<()> {
1789 let db = Connection::open_in_memory()?;
1790 assert!(!db.is_busy());
1791 let mut stmt = db.prepare("PRAGMA schema_version")?;
1792 assert!(!db.is_busy());
1793 {
1794 let mut rows = stmt.query([])?;
1795 assert!(!db.is_busy());
1796 let row = rows.next()?;
1797 assert!(db.is_busy());
1798 assert!(row.is_some());
1799 }
1800 assert!(!db.is_busy());
1801 Ok(())
1802 }
1803
1804 #[test]
1805 fn test_statement_debugging() -> Result<()> {
1806 let db = Connection::open_in_memory()?;
1807 let query = "SELECT 12345";
1808 let stmt = db.prepare(query)?;
1809
1810 assert!(format!("{stmt:?}").contains(query));
1811 Ok(())
1812 }
1813
1814 #[test]
1815 fn test_notnull_constraint_error() -> Result<()> {
1816 let db = Connection::open_in_memory()?;
1817 db.execute_batch("CREATE TABLE foo(x NOT NULL)")?;
1818
1819 let result = db.execute("INSERT INTO foo (x) VALUES (NULL)", []);
1820
1821 match result.unwrap_err() {
1822 Error::SqliteFailure(err, _) => {
1823 assert_eq!(err.code, ErrorCode::ConstraintViolation);
1824 assert_eq!(err.extended_code, ffi::SQLITE_CONSTRAINT_NOTNULL);
1825 }
1826 err => panic!("Unexpected error {err}"),
1827 }
1828 Ok(())
1829 }
1830
1831 #[test]
1832 fn test_version_string() {
1833 let n = version_number();
1834 let major = n / 1_000_000;
1835 let minor = (n % 1_000_000) / 1_000;
1836 let patch = n % 1_000;
1837
1838 assert!(version().contains(&format!("{major}.{minor}.{patch}")));
1839 }
1840
1841 #[test]
1842 #[cfg(feature = "functions")]
1843 fn test_interrupt() -> Result<()> {
1844 let db = Connection::open_in_memory()?;
1845
1846 let interrupt_handle = db.get_interrupt_handle();
1847
1848 db.create_scalar_function(
1849 "interrupt",
1850 0,
1851 functions::FunctionFlags::default(),
1852 move |_| {
1853 interrupt_handle.interrupt();
1854 Ok(0)
1855 },
1856 )?;
1857
1858 let mut stmt =
1859 db.prepare("SELECT interrupt() FROM (SELECT 1 UNION SELECT 2 UNION SELECT 3)")?;
1860
1861 let result: Result<Vec<i32>> = stmt.query([])?.map(|r| r.get(0)).collect();
1862
1863 assert_eq!(
1864 result.unwrap_err().sqlite_error_code(),
1865 Some(ErrorCode::OperationInterrupted)
1866 );
1867 Ok(())
1868 }
1869
1870 #[test]
1871 fn test_interrupt_close() {
1872 let db = checked_memory_handle();
1873 let handle = db.get_interrupt_handle();
1874 handle.interrupt();
1875 db.close().unwrap();
1876 handle.interrupt();
1877
1878 let db_guard = handle.db_lock.lock().unwrap();
1880 assert!(db_guard.is_null());
1881 }
1885
1886 #[test]
1887 fn test_get_raw() -> Result<()> {
1888 let db = Connection::open_in_memory()?;
1889 db.execute_batch("CREATE TABLE foo(i, x);")?;
1890 let vals = ["foobar", "1234", "qwerty"];
1891 let mut insert_stmt = db.prepare("INSERT INTO foo(i, x) VALUES(?1, ?2)")?;
1892 for (i, v) in vals.iter().enumerate() {
1893 let i_to_insert = i as i64;
1894 assert_eq!(insert_stmt.execute(params![i_to_insert, v])?, 1);
1895 }
1896
1897 let mut query = db.prepare("SELECT i, x FROM foo")?;
1898 let mut rows = query.query([])?;
1899
1900 while let Some(row) = rows.next()? {
1901 let i = row.get_ref(0)?.as_i64()?;
1902 let expect = vals[i as usize];
1903 let x = row.get_ref("x")?.as_str()?;
1904 assert_eq!(x, expect);
1905 }
1906
1907 let mut query = db.prepare("SELECT x FROM foo")?;
1908 let rows = query.query_map([], |row| {
1909 let x = row.get_ref(0)?.as_str()?; Ok(x[..].to_owned())
1911 })?;
1912
1913 for (i, row) in rows.enumerate() {
1914 assert_eq!(row?, vals[i]);
1915 }
1916 Ok(())
1917 }
1918
1919 #[test]
1920 fn test_from_handle() -> Result<()> {
1921 let db = Connection::open_in_memory()?;
1922 let handle = unsafe { db.handle() };
1923 {
1924 let db = unsafe { Connection::from_handle(handle) }?;
1925 db.execute_batch("PRAGMA VACUUM")?;
1926 }
1927 db.close().unwrap();
1928 Ok(())
1929 }
1930
1931 #[test]
1932 fn test_from_handle_owned() -> Result<()> {
1933 let mut handle: *mut ffi::sqlite3 = std::ptr::null_mut();
1934 let r = unsafe { ffi::sqlite3_open(c":memory:".as_ptr(), &mut handle) };
1935 assert_eq!(r, ffi::SQLITE_OK);
1936 let db = unsafe { Connection::from_handle_owned(handle) }?;
1937 db.execute_batch("PRAGMA VACUUM")?;
1938 Ok(())
1939 }
1940
1941 mod query_and_then_tests {
1942
1943 use super::*;
1944
1945 #[derive(Debug)]
1946 enum CustomError {
1947 SomeError,
1948 Sqlite(Error),
1949 }
1950
1951 impl fmt::Display for CustomError {
1952 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1953 match *self {
1954 CustomError::SomeError => write!(f, "my custom error"),
1955 CustomError::Sqlite(ref se) => write!(f, "my custom error: {se}"),
1956 }
1957 }
1958 }
1959
1960 impl StdError for CustomError {
1961 fn description(&self) -> &str {
1962 "my custom error"
1963 }
1964
1965 fn cause(&self) -> Option<&dyn StdError> {
1966 match *self {
1967 CustomError::SomeError => None,
1968 CustomError::Sqlite(ref se) => Some(se),
1969 }
1970 }
1971 }
1972
1973 impl From<Error> for CustomError {
1974 fn from(se: Error) -> CustomError {
1975 CustomError::Sqlite(se)
1976 }
1977 }
1978
1979 type CustomResult<T> = Result<T, CustomError>;
1980
1981 #[test]
1982 fn test_query_and_then() -> Result<()> {
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: Result<Vec<String>> =
1995 query.query_and_then([], |row| row.get(1))?.collect();
1996
1997 assert_eq!(results?.concat(), "hello, world!");
1998 Ok(())
1999 }
2000
2001 #[test]
2002 fn test_query_and_then_fails() -> Result<()> {
2003 let db = Connection::open_in_memory()?;
2004 let sql = "BEGIN;
2005 CREATE TABLE foo(x INTEGER, y TEXT);
2006 INSERT INTO foo VALUES(4, \"hello\");
2007 INSERT INTO foo VALUES(3, \", \");
2008 INSERT INTO foo VALUES(2, \"world\");
2009 INSERT INTO foo VALUES(1, \"!\");
2010 END;";
2011 db.execute_batch(sql)?;
2012
2013 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
2014 let bad_type: Result<Vec<f64>> = query.query_and_then([], |row| row.get(1))?.collect();
2015
2016 match bad_type.unwrap_err() {
2017 Error::InvalidColumnType(..) => (),
2018 err => panic!("Unexpected error {err}"),
2019 }
2020
2021 let bad_idx: Result<Vec<String>> =
2022 query.query_and_then([], |row| row.get(3))?.collect();
2023
2024 match bad_idx.unwrap_err() {
2025 Error::InvalidColumnIndex(_) => (),
2026 err => panic!("Unexpected error {err}"),
2027 }
2028 Ok(())
2029 }
2030
2031 #[test]
2032 fn test_query_and_then_custom_error() -> CustomResult<()> {
2033 let db = Connection::open_in_memory()?;
2034 let sql = "BEGIN;
2035 CREATE TABLE foo(x INTEGER, y TEXT);
2036 INSERT INTO foo VALUES(4, \"hello\");
2037 INSERT INTO foo VALUES(3, \", \");
2038 INSERT INTO foo VALUES(2, \"world\");
2039 INSERT INTO foo VALUES(1, \"!\");
2040 END;";
2041 db.execute_batch(sql)?;
2042
2043 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
2044 let results: CustomResult<Vec<String>> = query
2045 .query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite))?
2046 .collect();
2047
2048 assert_eq!(results?.concat(), "hello, world!");
2049 Ok(())
2050 }
2051
2052 #[test]
2053 fn test_query_and_then_custom_error_fails() -> Result<()> {
2054 let db = Connection::open_in_memory()?;
2055 let sql = "BEGIN;
2056 CREATE TABLE foo(x INTEGER, y TEXT);
2057 INSERT INTO foo VALUES(4, \"hello\");
2058 INSERT INTO foo VALUES(3, \", \");
2059 INSERT INTO foo VALUES(2, \"world\");
2060 INSERT INTO foo VALUES(1, \"!\");
2061 END;";
2062 db.execute_batch(sql)?;
2063
2064 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
2065 let bad_type: CustomResult<Vec<f64>> = query
2066 .query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite))?
2067 .collect();
2068
2069 match bad_type.unwrap_err() {
2070 CustomError::Sqlite(Error::InvalidColumnType(..)) => (),
2071 err => panic!("Unexpected error {err}"),
2072 }
2073
2074 let bad_idx: CustomResult<Vec<String>> = query
2075 .query_and_then([], |row| row.get(3).map_err(CustomError::Sqlite))?
2076 .collect();
2077
2078 match bad_idx.unwrap_err() {
2079 CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
2080 err => panic!("Unexpected error {err}"),
2081 }
2082
2083 let non_sqlite_err: CustomResult<Vec<String>> = query
2084 .query_and_then([], |_| Err(CustomError::SomeError))?
2085 .collect();
2086
2087 match non_sqlite_err.unwrap_err() {
2088 CustomError::SomeError => (),
2089 err => panic!("Unexpected error {err}"),
2090 }
2091 Ok(())
2092 }
2093
2094 #[test]
2095 fn test_query_row_and_then_custom_error() -> CustomResult<()> {
2096 let db = Connection::open_in_memory()?;
2097 let sql = "BEGIN;
2098 CREATE TABLE foo(x INTEGER, y TEXT);
2099 INSERT INTO foo VALUES(4, \"hello\");
2100 END;";
2101 db.execute_batch(sql)?;
2102
2103 let query = "SELECT x, y FROM foo ORDER BY x DESC";
2104 let results: CustomResult<String> =
2105 db.query_row_and_then(query, [], |row| row.get(1).map_err(CustomError::Sqlite));
2106
2107 assert_eq!(results?, "hello");
2108 Ok(())
2109 }
2110
2111 #[test]
2112 fn test_query_row_and_then_custom_error_fails() -> Result<()> {
2113 let db = Connection::open_in_memory()?;
2114 let sql = "BEGIN;
2115 CREATE TABLE foo(x INTEGER, y TEXT);
2116 INSERT INTO foo VALUES(4, \"hello\");
2117 END;";
2118 db.execute_batch(sql)?;
2119
2120 let query = "SELECT x, y FROM foo ORDER BY x DESC";
2121 let bad_type: CustomResult<f64> =
2122 db.query_row_and_then(query, [], |row| row.get(1).map_err(CustomError::Sqlite));
2123
2124 match bad_type.unwrap_err() {
2125 CustomError::Sqlite(Error::InvalidColumnType(..)) => (),
2126 err => panic!("Unexpected error {err}"),
2127 }
2128
2129 let bad_idx: CustomResult<String> =
2130 db.query_row_and_then(query, [], |row| row.get(3).map_err(CustomError::Sqlite));
2131
2132 match bad_idx.unwrap_err() {
2133 CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
2134 err => panic!("Unexpected error {err}"),
2135 }
2136
2137 let non_sqlite_err: CustomResult<String> =
2138 db.query_row_and_then(query, [], |_| Err(CustomError::SomeError));
2139
2140 match non_sqlite_err.unwrap_err() {
2141 CustomError::SomeError => (),
2142 err => panic!("Unexpected error {err}"),
2143 }
2144 Ok(())
2145 }
2146 }
2147
2148 #[test]
2149 fn test_dynamic() -> Result<()> {
2150 let db = Connection::open_in_memory()?;
2151 let sql = "BEGIN;
2152 CREATE TABLE foo(x INTEGER, y TEXT);
2153 INSERT INTO foo VALUES(4, \"hello\");
2154 END;";
2155 db.execute_batch(sql)?;
2156
2157 db.query_row("SELECT * FROM foo", [], |r| {
2158 assert_eq!(2, r.as_ref().column_count());
2159 Ok(())
2160 })
2161 }
2162 #[test]
2163 fn test_dyn_box() -> Result<()> {
2164 let db = Connection::open_in_memory()?;
2165 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
2166 let b: Box<dyn ToSql> = Box::new(5);
2167 db.execute("INSERT INTO foo VALUES(?1)", [b])?;
2168 db.query_row("SELECT x FROM foo", [], |r| {
2169 assert_eq!(5, r.get_unwrap::<_, i32>(0));
2170 Ok(())
2171 })
2172 }
2173
2174 #[test]
2175 fn test_params() -> Result<()> {
2176 let db = Connection::open_in_memory()?;
2177 db.query_row(
2178 "SELECT
2179 ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10,
2180 ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19, ?20,
2181 ?21, ?22, ?23, ?24, ?25, ?26, ?27, ?28, ?29, ?30,
2182 ?31, ?32, ?33, ?34;",
2183 params![
2184 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,
2185 1, 1, 1, 1, 1, 1,
2186 ],
2187 |r| {
2188 assert_eq!(1, r.get_unwrap::<_, i32>(0));
2189 Ok(())
2190 },
2191 )
2192 }
2193
2194 #[test]
2195 #[cfg(not(feature = "extra_check"))]
2196 fn test_alter_table() -> Result<()> {
2197 let db = Connection::open_in_memory()?;
2198 db.execute_batch("CREATE TABLE x(t);")?;
2199 db.execute("ALTER TABLE x RENAME TO y;", [])?;
2201 Ok(())
2202 }
2203
2204 #[test]
2205 fn test_batch() -> Result<()> {
2206 let db = Connection::open_in_memory()?;
2207 let sql = r"
2208 CREATE TABLE tbl1 (col);
2209 CREATE TABLE tbl2 (col);
2210 ";
2211 let batch = Batch::new(&db, sql);
2212 for stmt in batch {
2213 let mut stmt = stmt?;
2214 stmt.execute([])?;
2215 }
2216 Ok(())
2217 }
2218
2219 #[test]
2220 #[cfg(feature = "modern_sqlite")]
2221 fn test_returning() -> Result<()> {
2222 let db = Connection::open_in_memory()?;
2223 db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)")?;
2224 let row_id = db.one_column::<i64>("INSERT INTO foo DEFAULT VALUES RETURNING ROWID")?;
2225 assert_eq!(row_id, 1);
2226 Ok(())
2227 }
2228
2229 #[test]
2230 fn test_cache_flush() -> Result<()> {
2231 let db = Connection::open_in_memory()?;
2232 db.cache_flush()
2233 }
2234
2235 #[test]
2236 fn db_readonly() -> Result<()> {
2237 let db = Connection::open_in_memory()?;
2238 assert!(!db.is_readonly(MAIN_DB)?);
2239 Ok(())
2240 }
2241
2242 #[test]
2243 #[cfg(feature = "rusqlite-macros")]
2244 fn prepare_and_bind() -> Result<()> {
2245 let db = Connection::open_in_memory()?;
2246 let name = "Lisa";
2247 let age = 8;
2248 let mut stmt = prepare_and_bind!(db, "SELECT $name, $age;");
2249 let (v1, v2) = stmt
2250 .raw_query()
2251 .next()
2252 .and_then(|o| o.ok_or(Error::QueryReturnedNoRows))
2253 .and_then(|r| Ok((r.get::<_, String>(0)?, r.get::<_, i64>(1)?)))?;
2254 assert_eq!((v1.as_str(), v2), (name, age));
2255 Ok(())
2256 }
2257
2258 #[test]
2259 #[cfg(feature = "modern_sqlite")]
2260 fn test_db_name() -> Result<()> {
2261 let db = Connection::open_in_memory()?;
2262 assert_eq!(db.db_name(0).unwrap(), "main");
2263 assert_eq!(db.db_name(1).unwrap(), "temp");
2264 assert_eq!(db.db_name(2), Err(Error::InvalidDatabaseIndex(2)));
2265 db.execute_batch("ATTACH DATABASE ':memory:' AS xyz;")?;
2266 assert_eq!(db.db_name(2).unwrap(), "xyz");
2267 Ok(())
2268 }
2269
2270 #[test]
2271 #[cfg(feature = "modern_sqlite")]
2272 fn test_is_interrupted() -> Result<()> {
2273 let db = Connection::open_in_memory()?;
2274 assert!(!db.is_interrupted());
2275 db.get_interrupt_handle().interrupt();
2276 assert!(db.is_interrupted());
2277 Ok(())
2278 }
2279}