1#![warn(missing_docs)]
55#![cfg_attr(docsrs, feature(doc_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::{CStr, CString};
64use std::fmt;
65use std::os::raw::{c_char, c_int};
66
67use std::path::Path;
68use std::result;
69use std::str;
70use std::sync::{Arc, Mutex};
71
72use crate::cache::StatementCache;
73use crate::inner_connection::InnerConnection;
74use crate::raw_statement::RawStatement;
75use crate::types::ValueRef;
76
77pub use crate::cache::CachedStatement;
78#[cfg(feature = "column_decltype")]
79pub use crate::column::Column;
80pub use crate::error::{to_sqlite_error, Error};
81pub use crate::ffi::ErrorCode;
82#[cfg(feature = "load_extension")]
83pub use crate::load_extension_guard::LoadExtensionGuard;
84pub use crate::params::{params_from_iter, Params, ParamsFromIter};
85pub use crate::row::{AndThenRows, Map, MappedRows, Row, RowIndex, Rows};
86pub use crate::statement::{Statement, StatementStatus};
87#[cfg(feature = "modern_sqlite")]
88pub use crate::transaction::TransactionState;
89pub use crate::transaction::{DropBehavior, Savepoint, Transaction, TransactionBehavior};
90pub use crate::types::ToSql;
91pub use crate::version::*;
92#[cfg(feature = "rusqlite-macros")]
93#[doc(hidden)]
94pub use rusqlite_macros::__bind;
95
96#[macro_use]
97mod error;
98
99#[cfg(not(feature = "loadable_extension"))]
100pub mod auto_extension;
101#[cfg(feature = "backup")]
102#[cfg_attr(docsrs, doc(cfg(feature = "backup")))]
103pub mod backup;
104#[cfg(feature = "blob")]
105#[cfg_attr(docsrs, doc(cfg(feature = "blob")))]
106pub mod blob;
107mod busy;
108mod cache;
109#[cfg(feature = "collation")]
110#[cfg_attr(docsrs, doc(cfg(feature = "collation")))]
111mod collation;
112mod column;
113pub mod config;
114#[cfg(any(feature = "functions", feature = "vtab"))]
115mod context;
116#[cfg(feature = "functions")]
117#[cfg_attr(docsrs, doc(cfg(feature = "functions")))]
118pub mod functions;
119#[cfg(feature = "hooks")]
120#[cfg_attr(docsrs, doc(cfg(feature = "hooks")))]
121pub mod hooks;
122mod inner_connection;
123#[cfg(feature = "limits")]
124#[cfg_attr(docsrs, doc(cfg(feature = "limits")))]
125pub mod limits;
126#[cfg(feature = "load_extension")]
127mod load_extension_guard;
128mod params;
129mod pragma;
130mod raw_statement;
131mod row;
132#[cfg(feature = "serialize")]
133#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
134pub mod serialize;
135#[cfg(feature = "session")]
136#[cfg_attr(docsrs, doc(cfg(feature = "session")))]
137pub mod session;
138mod statement;
139#[cfg(feature = "trace")]
140#[cfg_attr(docsrs, doc(cfg(feature = "trace")))]
141pub mod trace;
142mod transaction;
143pub mod types;
144#[cfg(feature = "unlock_notify")]
145mod unlock_notify;
146mod version;
147#[cfg(feature = "vtab")]
148#[cfg_attr(docsrs, doc(cfg(feature = "vtab")))]
149pub mod vtab;
150
151#[cfg(feature = "vtab")]
152#[cfg_attr(docsrs, doc(cfg(feature = "vtab")))]
153mod twizzler;
154
155pub(crate) mod util;
156pub(crate) use util::SmallCString;
157
158const STATEMENT_CACHE_DEFAULT_CAPACITY: usize = 16;
160
161#[macro_export]
184macro_rules! params {
185 () => {
186 &[] as &[&dyn $crate::ToSql]
187 };
188 ($($param:expr),+ $(,)?) => {
189 &[$(&$param as &dyn $crate::ToSql),+] as &[&dyn $crate::ToSql]
190 };
191}
192
193#[macro_export]
221macro_rules! named_params {
222 () => {
223 &[] as &[(&str, &dyn $crate::ToSql)]
224 };
225 ($($param_name:literal: $param_val:expr),+ $(,)?) => {
228 &[$(($param_name, &$param_val as &dyn $crate::ToSql)),+] as &[(&str, &dyn $crate::ToSql)]
229 };
230}
231
232#[cfg(feature = "rusqlite-macros")]
251#[cfg_attr(docsrs, doc(cfg(feature = "rusqlite-macros")))]
252#[macro_export]
253macro_rules! prepare_and_bind {
254 ($conn:expr, $sql:literal) => {{
255 let mut stmt = $conn.prepare($sql)?;
256 $crate::__bind!(stmt $sql);
257 stmt
258 }};
259}
260
261#[cfg(feature = "rusqlite-macros")]
267#[cfg_attr(docsrs, doc(cfg(feature = "rusqlite-macros")))]
268#[macro_export]
269macro_rules! prepare_cached_and_bind {
270 ($conn:expr, $sql:literal) => {{
271 let mut stmt = $conn.prepare_cached($sql)?;
272 $crate::__bind!(stmt $sql);
273 stmt
274 }};
275}
276
277pub type Result<T, E = Error> = result::Result<T, E>;
279
280pub trait OptionalExtension<T> {
282 fn optional(self) -> Result<Option<T>>;
288}
289
290impl<T> OptionalExtension<T> for Result<T> {
291 fn optional(self) -> Result<Option<T>> {
292 match self {
293 Ok(value) => Ok(Some(value)),
294 Err(Error::QueryReturnedNoRows) => Ok(None),
295 Err(e) => Err(e),
296 }
297 }
298}
299
300unsafe fn errmsg_to_string(errmsg: *const c_char) -> String {
301 CStr::from_ptr(errmsg).to_string_lossy().into_owned()
302}
303
304fn str_to_cstring(s: &str) -> Result<SmallCString> {
305 Ok(SmallCString::new(s)?)
306}
307
308fn str_for_sqlite(s: &[u8]) -> Result<(*const c_char, c_int, ffi::sqlite3_destructor_type)> {
315 let len = len_as_c_int(s.len())?;
316 let (ptr, dtor_info) = if len != 0 {
317 (s.as_ptr().cast::<c_char>(), ffi::SQLITE_TRANSIENT())
318 } else {
319 ("".as_ptr().cast::<c_char>(), ffi::SQLITE_STATIC())
321 };
322 Ok((ptr, len, dtor_info))
323}
324
325fn len_as_c_int(len: usize) -> Result<c_int> {
328 if len >= (c_int::MAX as usize) {
329 Err(err!(ffi::SQLITE_TOOBIG))
330 } else {
331 Ok(len as c_int)
332 }
333}
334
335#[cfg(unix)]
336fn path_to_cstring(p: &Path) -> Result<CString> {
337 use std::os::unix::ffi::OsStrExt;
338 Ok(CString::new(p.as_os_str().as_bytes())?)
339}
340
341#[cfg(not(unix))]
342fn path_to_cstring(p: &Path) -> Result<CString> {
343 let s = p.to_str().ok_or_else(|| Error::InvalidPath(p.to_owned()))?;
344 Ok(CString::new(s)?)
345}
346
347#[derive(Copy, Clone, Debug, PartialEq, Eq)]
349pub enum DatabaseName<'a> {
350 Main,
352 Temp,
354 Attached(&'a str),
356 C(&'a CStr),
358}
359
360pub const MAIN_DB: DatabaseName<'static> = DatabaseName::Main;
362
363pub const TEMP_DB: DatabaseName<'static> = DatabaseName::Temp;
365
366impl DatabaseName<'_> {
367 #[inline]
368 fn as_cstr(&self) -> Result<std::borrow::Cow<'_, CStr>> {
369 Ok(match *self {
370 DatabaseName::Main => std::borrow::Cow::Borrowed(c"main"),
371 DatabaseName::Temp => std::borrow::Cow::Borrowed(c"temp"),
372 DatabaseName::Attached(s) => std::borrow::Cow::Owned(CString::new(s)?),
373 DatabaseName::C(s) => std::borrow::Cow::Borrowed(s),
374 })
375 }
376 #[cfg(feature = "hooks")]
377 pub(crate) fn from_cstr(cs: &std::ffi::CStr) -> DatabaseName<'_> {
378 if cs == c"main" {
379 DatabaseName::Main
380 } else if cs == c"temp" {
381 DatabaseName::Temp
382 } else {
383 DatabaseName::C(cs)
384 }
385 }
386}
387
388pub struct Connection {
390 db: RefCell<InnerConnection>,
391 cache: StatementCache,
392 transaction_behavior: TransactionBehavior,
393}
394
395unsafe impl Send for Connection {}
396
397impl Drop for Connection {
398 #[inline]
399 fn drop(&mut self) {
400 self.flush_prepared_statement_cache();
401 }
402}
403
404impl Connection {
405 #[inline]
458 pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
459 let flags = OpenFlags::default();
460
461 let conn = Self::open_with_flags(path, flags)?;
462
463 #[cfg(target_os = "twizzler")]
464 conn.setup_twz_vtab();
465
466 Ok(conn)
467 }
468
469 #[inline]
475 pub fn open_in_memory() -> Result<Self> {
476 let flags = OpenFlags::default();
477 let conn = Self::open_in_memory_with_flags(flags)?;
478
479 #[cfg(target_os = "twizzler")]
480 conn.setup_twz_vtab();
481
482 Ok(conn)
483 }
484
485 #[inline]
495 pub fn open_with_flags<P: AsRef<Path>>(path: P, flags: OpenFlags) -> Result<Self> {
496 let c_path = path_to_cstring(path.as_ref())?;
497 let conn = InnerConnection::open_with_flags(&c_path, flags, None).map(|db| Self {
498 db: RefCell::new(db),
499 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
500 transaction_behavior: TransactionBehavior::Deferred,
501 })?;
502
503 #[cfg(target_os = "twizzler")]
504 conn.setup_twz_vtab();
505
506 Ok(conn)
507 }
508
509 #[inline]
520 pub fn open_with_flags_and_vfs<P: AsRef<Path>>(
521 path: P,
522 flags: OpenFlags,
523 vfs: &str,
524 ) -> Result<Self> {
525 let c_path = path_to_cstring(path.as_ref())?;
526 let c_vfs = str_to_cstring(vfs)?;
527 let conn = InnerConnection::open_with_flags(&c_path, flags, Some(&c_vfs)).map(|db| Self {
528 db: RefCell::new(db),
529 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
530 transaction_behavior: TransactionBehavior::Deferred,
531 })?;
532
533 #[cfg(target_os = "twizzler")]
534 conn.setup_twz_vtab();
535
536 Ok(conn)
537 }
538
539 #[inline]
548 pub fn open_in_memory_with_flags(flags: OpenFlags) -> Result<Self> {
549 Self::open_with_flags(":memory:", flags)
550 }
551
552 #[inline]
563 pub fn open_in_memory_with_flags_and_vfs(flags: OpenFlags, vfs: &str) -> Result<Self> {
564 Self::open_with_flags_and_vfs(":memory:", flags, vfs)
565 }
566
567 pub fn execute_batch(&self, sql: &str) -> Result<()> {
589 let mut sql = sql;
590 while !sql.is_empty() {
591 let stmt = self.prepare(sql)?;
592 if !stmt.stmt.is_null() && stmt.step()? && cfg!(feature = "extra_check") {
593 return Err(Error::ExecuteReturnedResults);
595 }
596 let tail = stmt.stmt.tail();
597 if tail == 0 || tail >= sql.len() {
598 break;
599 }
600 sql = &sql[tail..];
601 }
602 Ok(())
603 }
604
605 #[inline]
656 pub fn execute<P: Params>(&self, sql: &str, params: P) -> Result<usize> {
657 self.prepare(sql)
658 .and_then(|mut stmt| stmt.check_no_tail().and_then(|()| stmt.execute(params)))
659 }
660
661 #[inline]
669 pub fn path(&self) -> Option<&str> {
670 unsafe { crate::inner_connection::db_filename(self.handle(), DatabaseName::Main) }
671 }
672
673 #[inline]
678 pub fn release_memory(&self) -> Result<()> {
679 self.db.borrow_mut().release_memory()
680 }
681
682 #[inline]
687 pub fn last_insert_rowid(&self) -> i64 {
688 self.db.borrow_mut().last_insert_rowid()
689 }
690
691 #[inline]
719 pub fn query_row<T, P, F>(&self, sql: &str, params: P, f: F) -> Result<T>
720 where
721 P: Params,
722 F: FnOnce(&Row<'_>) -> Result<T>,
723 {
724 let mut stmt = self.prepare(sql)?;
725 stmt.check_no_tail()?;
726 stmt.query_row(params, f)
727 }
728
729 #[cfg(test)]
731 pub(crate) fn one_column<T: types::FromSql>(&self, sql: &str) -> Result<T> {
732 self.query_row(sql, [], |r| r.get(0))
733 }
734
735 #[inline]
761 pub fn query_row_and_then<T, E, P, F>(&self, sql: &str, params: P, f: F) -> Result<T, E>
762 where
763 P: Params,
764 F: FnOnce(&Row<'_>) -> Result<T, E>,
765 E: From<Error>,
766 {
767 let mut stmt = self.prepare(sql)?;
768 stmt.check_no_tail()?;
769 let mut rows = stmt.query(params)?;
770
771 rows.get_expected_row().map_err(E::from).and_then(f)
772 }
773
774 #[inline]
793 pub fn prepare(&self, sql: &str) -> Result<Statement<'_>> {
794 self.prepare_with_flags(sql, PrepFlags::default())
795 }
796
797 #[inline]
804 pub fn prepare_with_flags(&self, sql: &str, flags: PrepFlags) -> Result<Statement<'_>> {
805 self.db.borrow_mut().prepare(self, sql, flags)
806 }
807
808 #[inline]
818 pub fn close(self) -> Result<(), (Self, Error)> {
819 self.flush_prepared_statement_cache();
820 let r = self.db.borrow_mut().close();
821 r.map_err(move |err| (self, err))
822 }
823
824 #[cfg(feature = "load_extension")]
877 #[cfg_attr(docsrs, doc(cfg(feature = "load_extension")))]
878 #[inline]
879 pub unsafe fn load_extension_enable(&self) -> Result<()> {
880 self.db.borrow_mut().enable_load_extension(1)
881 }
882
883 #[cfg(feature = "load_extension")]
891 #[cfg_attr(docsrs, doc(cfg(feature = "load_extension")))]
892 #[inline]
893 pub fn load_extension_disable(&self) -> Result<()> {
894 unsafe { self.db.borrow_mut().enable_load_extension(0) }
896 }
897
898 #[cfg(feature = "load_extension")]
934 #[cfg_attr(docsrs, doc(cfg(feature = "load_extension")))]
935 #[inline]
936 pub unsafe fn load_extension<P: AsRef<Path>>(
937 &self,
938 dylib_path: P,
939 entry_point: Option<&str>,
940 ) -> Result<()> {
941 self.db
942 .borrow_mut()
943 .load_extension(dylib_path.as_ref(), entry_point)
944 }
945
946 #[inline]
960 pub unsafe fn handle(&self) -> *mut ffi::sqlite3 {
961 self.db.borrow().db()
962 }
963
964 #[inline]
973 pub unsafe fn from_handle(db: *mut ffi::sqlite3) -> Result<Self> {
974 let db = InnerConnection::new(db, false);
975 Ok(Self {
976 db: RefCell::new(db),
977 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
978 transaction_behavior: TransactionBehavior::Deferred,
979 })
980 }
981
982 #[cfg(feature = "loadable_extension")]
988 #[cfg_attr(docsrs, doc(cfg(feature = "loadable_extension")))]
989 pub unsafe fn extension_init2(
990 db: *mut ffi::sqlite3,
991 pz_err_msg: *mut *mut c_char,
992 p_api: *mut ffi::sqlite3_api_routines,
993 init: fn(Self) -> Result<bool>,
994 ) -> c_int {
995 if p_api.is_null() {
996 return ffi::SQLITE_ERROR;
997 }
998 match ffi::rusqlite_extension_init2(p_api)
999 .map_err(Error::from)
1000 .and(Self::from_handle(db))
1001 .and_then(init)
1002 {
1003 Err(err) => to_sqlite_error(&err, pz_err_msg),
1004 Ok(true) => ffi::SQLITE_OK_LOAD_PERMANENTLY,
1005 _ => ffi::SQLITE_OK,
1006 }
1007 }
1008
1009 #[inline]
1022 pub unsafe fn from_handle_owned(db: *mut ffi::sqlite3) -> Result<Self> {
1023 let db = InnerConnection::new(db, true);
1024 Ok(Self {
1025 db: RefCell::new(db),
1026 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
1027 transaction_behavior: TransactionBehavior::Deferred,
1028 })
1029 }
1030
1031 #[inline]
1034 pub fn get_interrupt_handle(&self) -> InterruptHandle {
1035 self.db.borrow().get_interrupt_handle()
1036 }
1037
1038 #[inline]
1039 fn decode_result(&self, code: c_int) -> Result<()> {
1040 self.db.borrow().decode_result(code)
1041 }
1042
1043 #[inline]
1049 pub fn changes(&self) -> u64 {
1050 self.db.borrow().changes()
1051 }
1052
1053 #[inline]
1059 pub fn total_changes(&self) -> u64 {
1060 self.db.borrow().total_changes()
1061 }
1062
1063 #[inline]
1066 pub fn is_autocommit(&self) -> bool {
1067 self.db.borrow().is_autocommit()
1068 }
1069
1070 #[inline]
1072 pub fn is_busy(&self) -> bool {
1073 self.db.borrow().is_busy()
1074 }
1075
1076 pub fn cache_flush(&self) -> Result<()> {
1078 self.db.borrow_mut().cache_flush()
1079 }
1080
1081 pub fn is_readonly(&self, db_name: DatabaseName<'_>) -> Result<bool> {
1083 self.db.borrow().db_readonly(db_name)
1084 }
1085
1086 #[cfg(feature = "modern_sqlite")] #[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
1093 pub fn db_name(&self, index: usize) -> Result<String> {
1094 unsafe {
1095 let db = self.handle();
1096 let name = ffi::sqlite3_db_name(db, index as c_int);
1097 if name.is_null() {
1098 Err(Error::InvalidDatabaseIndex(index))
1099 } else {
1100 Ok(CStr::from_ptr(name).to_str()?.to_owned())
1101 }
1102 }
1103 }
1104
1105 #[cfg(feature = "modern_sqlite")] #[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
1108 pub fn is_interrupted(&self) -> bool {
1109 self.db.borrow().is_interrupted()
1110 }
1111}
1112
1113impl fmt::Debug for Connection {
1114 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1115 f.debug_struct("Connection")
1116 .field("path", &self.path())
1117 .finish()
1118 }
1119}
1120
1121#[derive(Debug)]
1146pub struct Batch<'conn, 'sql> {
1147 conn: &'conn Connection,
1148 sql: &'sql str,
1149 tail: usize,
1150}
1151
1152impl<'conn, 'sql> Batch<'conn, 'sql> {
1153 pub fn new(conn: &'conn Connection, sql: &'sql str) -> Self {
1155 Batch { conn, sql, tail: 0 }
1156 }
1157}
1158impl<'conn> fallible_iterator::FallibleIterator for Batch<'conn, '_> {
1159 type Error = Error;
1160 type Item = Statement<'conn>;
1161
1162 fn next(&mut self) -> Result<Option<Statement<'conn>>> {
1166 while self.tail < self.sql.len() {
1167 let sql = &self.sql[self.tail..];
1168 let next = self.conn.prepare(sql)?;
1169 let tail = next.stmt.tail();
1170 if tail == 0 {
1171 self.tail = self.sql.len();
1172 } else {
1173 self.tail += tail;
1174 }
1175 if next.stmt.is_null() {
1176 continue;
1177 }
1178 return Ok(Some(next));
1179 }
1180 Ok(None)
1181 }
1182}
1183
1184bitflags::bitflags! {
1185 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1192 #[repr(C)]
1193 pub struct OpenFlags: c_int {
1194 const SQLITE_OPEN_READ_ONLY = ffi::SQLITE_OPEN_READONLY;
1197 const SQLITE_OPEN_READ_WRITE = ffi::SQLITE_OPEN_READWRITE;
1201 const SQLITE_OPEN_CREATE = ffi::SQLITE_OPEN_CREATE;
1203 const SQLITE_OPEN_URI = ffi::SQLITE_OPEN_URI;
1205 const SQLITE_OPEN_MEMORY = ffi::SQLITE_OPEN_MEMORY;
1207 const SQLITE_OPEN_NO_MUTEX = ffi::SQLITE_OPEN_NOMUTEX;
1216 const SQLITE_OPEN_FULL_MUTEX = ffi::SQLITE_OPEN_FULLMUTEX;
1240 const SQLITE_OPEN_SHARED_CACHE = 0x0002_0000;
1247 const SQLITE_OPEN_PRIVATE_CACHE = 0x0004_0000;
1249 const SQLITE_OPEN_NOFOLLOW = 0x0100_0000;
1251 const SQLITE_OPEN_EXRESCODE = 0x0200_0000;
1253 }
1254}
1255
1256impl Default for OpenFlags {
1257 #[inline]
1258 fn default() -> Self {
1259 Self::SQLITE_OPEN_READ_WRITE
1262 | Self::SQLITE_OPEN_CREATE
1263 | Self::SQLITE_OPEN_NO_MUTEX
1264 | Self::SQLITE_OPEN_URI
1265 }
1266}
1267
1268bitflags::bitflags! {
1269 #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
1272 #[repr(C)]
1273 pub struct PrepFlags: ::std::os::raw::c_uint {
1274 const SQLITE_PREPARE_PERSISTENT = 0x01;
1276 const SQLITE_PREPARE_NO_VTAB = 0x04;
1278 const SQLITE_PREPARE_DONT_LOG = 0x10;
1280 }
1281}
1282
1283pub struct InterruptHandle {
1285 db_lock: Arc<Mutex<*mut ffi::sqlite3>>,
1286}
1287
1288unsafe impl Send for InterruptHandle {}
1289unsafe impl Sync for InterruptHandle {}
1290
1291impl InterruptHandle {
1292 pub fn interrupt(&self) {
1295 let db_handle = self.db_lock.lock().unwrap();
1296 if !db_handle.is_null() {
1297 unsafe { ffi::sqlite3_interrupt(*db_handle) }
1298 }
1299 }
1300}
1301
1302#[cfg(doctest)]
1303doc_comment::doctest!("../README.md");
1304
1305#[cfg(test)]
1306mod test {
1307 use super::*;
1308 use fallible_iterator::FallibleIterator;
1309 use std::error::Error as StdError;
1310 use std::fmt;
1311
1312 #[allow(dead_code)]
1316 #[expect(unconditional_recursion, clippy::extra_unused_type_parameters)]
1317 fn ensure_send<T: Send>() {
1318 ensure_send::<Connection>();
1319 ensure_send::<InterruptHandle>();
1320 }
1321
1322 #[allow(dead_code)]
1323 #[expect(unconditional_recursion, clippy::extra_unused_type_parameters)]
1324 fn ensure_sync<T: Sync>() {
1325 ensure_sync::<InterruptHandle>();
1326 }
1327
1328 fn checked_memory_handle() -> Connection {
1329 Connection::open_in_memory().unwrap()
1330 }
1331
1332 #[test]
1333 fn test_concurrent_transactions_busy_commit() -> Result<()> {
1334 use std::time::Duration;
1335 let tmp = tempfile::tempdir().unwrap();
1336 let path = tmp.path().join("transactions.db3");
1337
1338 Connection::open(&path)?.execute_batch(
1339 "
1340 BEGIN; CREATE TABLE foo(x INTEGER);
1341 INSERT INTO foo VALUES(42); END;",
1342 )?;
1343
1344 let mut db1 = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_WRITE)?;
1345 let mut db2 = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_ONLY)?;
1346
1347 db1.busy_timeout(Duration::from_millis(0))?;
1348 db2.busy_timeout(Duration::from_millis(0))?;
1349
1350 {
1351 let tx1 = db1.transaction()?;
1352 let tx2 = db2.transaction()?;
1353
1354 tx1.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))?;
1356 tx2.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))?;
1357
1358 tx1.execute("INSERT INTO foo VALUES(?1)", [1])?;
1359 let _ = tx2.execute("INSERT INTO foo VALUES(?1)", [2]);
1360
1361 let _ = tx1.commit();
1362 let _ = tx2.commit();
1363 }
1364
1365 let _ = db1
1366 .transaction()
1367 .expect("commit should have closed transaction");
1368 let _ = db2
1369 .transaction()
1370 .expect("commit should have closed transaction");
1371 Ok(())
1372 }
1373
1374 #[test]
1375 fn test_persistence() -> Result<()> {
1376 let temp_dir = tempfile::tempdir().unwrap();
1377 let path = temp_dir.path().join("test.db3");
1378
1379 {
1380 let db = Connection::open(&path)?;
1381 let sql = "BEGIN;
1382 CREATE TABLE foo(x INTEGER);
1383 INSERT INTO foo VALUES(42);
1384 END;";
1385 db.execute_batch(sql)?;
1386 }
1387
1388 let path_string = path.to_str().unwrap();
1389 let db = Connection::open(path_string)?;
1390 let the_answer: i64 = db.one_column("SELECT x FROM foo")?;
1391
1392 assert_eq!(42i64, the_answer);
1393 Ok(())
1394 }
1395
1396 #[test]
1397 fn test_open() {
1398 Connection::open_in_memory().unwrap();
1399
1400 let db = checked_memory_handle();
1401 db.close().unwrap();
1402 }
1403
1404 #[test]
1405 fn test_path() -> Result<()> {
1406 let tmp = tempfile::tempdir().unwrap();
1407 let db = Connection::open("")?;
1408 assert_eq!(Some(""), db.path());
1409 let db = Connection::open_in_memory()?;
1410 assert_eq!(Some(""), db.path());
1411 let db = Connection::open("file:dummy.db?mode=memory&cache=shared")?;
1412 assert_eq!(Some(""), db.path());
1413 let path = tmp.path().join("file.db");
1414 let db = Connection::open(path)?;
1415 assert!(db.path().is_some_and(|p| p.ends_with("file.db")));
1416 Ok(())
1417 }
1418
1419 #[test]
1420 fn test_open_failure() {
1421 let filename = "no_such_file.db";
1422 let result = Connection::open_with_flags(filename, OpenFlags::SQLITE_OPEN_READ_ONLY);
1423 let err = result.unwrap_err();
1424 if let Error::SqliteFailure(e, Some(msg)) = err {
1425 assert_eq!(ErrorCode::CannotOpen, e.code);
1426 assert_eq!(ffi::SQLITE_CANTOPEN, e.extended_code);
1427 assert!(
1428 msg.contains(filename),
1429 "error message '{msg}' does not contain '{filename}'"
1430 );
1431 } else {
1432 panic!("SqliteFailure expected");
1433 }
1434 }
1435
1436 #[cfg(unix)]
1437 #[test]
1438 fn test_invalid_unicode_file_names() -> Result<()> {
1439 use std::ffi::OsStr;
1440 use std::fs::File;
1441 use std::os::unix::ffi::OsStrExt;
1442 let temp_dir = tempfile::tempdir().unwrap();
1443
1444 let path = temp_dir.path();
1445 if File::create(path.join(OsStr::from_bytes(&[0xFE]))).is_err() {
1446 return Ok(());
1448 }
1449 let db_path = path.join(OsStr::from_bytes(&[0xFF]));
1450 {
1451 let db = Connection::open(&db_path)?;
1452 let sql = "BEGIN;
1453 CREATE TABLE foo(x INTEGER);
1454 INSERT INTO foo VALUES(42);
1455 END;";
1456 db.execute_batch(sql)?;
1457 }
1458
1459 let db = Connection::open(&db_path)?;
1460 let the_answer: i64 = db.one_column("SELECT x FROM foo")?;
1461
1462 assert_eq!(42i64, the_answer);
1463 Ok(())
1464 }
1465
1466 #[test]
1467 fn test_close_retry() -> Result<()> {
1468 let db = Connection::open_in_memory()?;
1469
1470 let raw_stmt = {
1474 use super::str_to_cstring;
1475 use std::os::raw::c_int;
1476 use std::ptr;
1477
1478 let raw_db = db.db.borrow_mut().db;
1479 let sql = "SELECT 1";
1480 let mut raw_stmt: *mut ffi::sqlite3_stmt = ptr::null_mut();
1481 let cstring = str_to_cstring(sql)?;
1482 let rc = unsafe {
1483 ffi::sqlite3_prepare_v2(
1484 raw_db,
1485 cstring.as_ptr(),
1486 (sql.len() + 1) as c_int,
1487 &mut raw_stmt,
1488 ptr::null_mut(),
1489 )
1490 };
1491 assert_eq!(rc, ffi::SQLITE_OK);
1492 raw_stmt
1493 };
1494
1495 let (db, _) = db.close().unwrap_err();
1498 let (db, _) = db.close().unwrap_err();
1499 let (db, _) = db.close().unwrap_err();
1500
1501 assert_eq!(ffi::SQLITE_OK, unsafe { ffi::sqlite3_finalize(raw_stmt) });
1503
1504 db.close().unwrap();
1505 Ok(())
1506 }
1507
1508 #[test]
1509 fn test_open_with_flags() {
1510 for bad_flags in &[
1511 OpenFlags::empty(),
1512 OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_READ_WRITE,
1513 OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_CREATE,
1514 ] {
1515 Connection::open_in_memory_with_flags(*bad_flags).unwrap_err();
1516 }
1517 }
1518
1519 #[test]
1520 fn test_execute_batch() -> Result<()> {
1521 let db = Connection::open_in_memory()?;
1522 let sql = "BEGIN;
1523 CREATE TABLE foo(x INTEGER);
1524 INSERT INTO foo VALUES(1);
1525 INSERT INTO foo VALUES(2);
1526 INSERT INTO foo VALUES(3);
1527 INSERT INTO foo VALUES(4);
1528 END;";
1529 db.execute_batch(sql)?;
1530
1531 db.execute_batch("UPDATE foo SET x = 3 WHERE x < 3")?;
1532
1533 db.execute_batch("INVALID SQL").unwrap_err();
1534 Ok(())
1535 }
1536
1537 #[test]
1538 fn test_execute() -> Result<()> {
1539 let db = Connection::open_in_memory()?;
1540 db.execute_batch("CREATE TABLE foo(x INTEGER)")?;
1541
1542 assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?1)", [1i32])?);
1543 assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?1)", [2i32])?);
1544
1545 assert_eq!(3i32, db.one_column::<i32>("SELECT SUM(x) FROM foo")?);
1546 Ok(())
1547 }
1548
1549 #[test]
1550 #[cfg(feature = "extra_check")]
1551 fn test_execute_select_with_no_row() {
1552 let db = checked_memory_handle();
1553 let err = db.execute("SELECT 1 WHERE 1 < ?1", [1i32]).unwrap_err();
1554 assert_eq!(
1555 err,
1556 Error::ExecuteReturnedResults,
1557 "Unexpected error: {err}"
1558 );
1559 }
1560
1561 #[test]
1562 fn test_execute_select_with_row() {
1563 let db = checked_memory_handle();
1564 let err = db.execute("SELECT 1", []).unwrap_err();
1565 assert_eq!(err, Error::ExecuteReturnedResults);
1566 }
1567
1568 #[test]
1569 #[cfg(feature = "extra_check")]
1570 fn test_execute_multiple() {
1571 let db = checked_memory_handle();
1572 let err = db
1573 .execute(
1574 "CREATE TABLE foo(x INTEGER); CREATE TABLE foo(x INTEGER)",
1575 [],
1576 )
1577 .unwrap_err();
1578 match err {
1579 Error::MultipleStatement => (),
1580 _ => panic!("Unexpected error: {err}"),
1581 }
1582 }
1583
1584 #[test]
1585 fn test_prepare_column_names() -> Result<()> {
1586 let db = Connection::open_in_memory()?;
1587 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1588
1589 let stmt = db.prepare("SELECT * FROM foo")?;
1590 assert_eq!(stmt.column_count(), 1);
1591 assert_eq!(stmt.column_names(), vec!["x"]);
1592
1593 let stmt = db.prepare("SELECT x AS a, x AS b FROM foo")?;
1594 assert_eq!(stmt.column_count(), 2);
1595 assert_eq!(stmt.column_names(), vec!["a", "b"]);
1596 Ok(())
1597 }
1598
1599 #[test]
1600 fn test_prepare_execute() -> 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 assert_eq!(insert_stmt.execute(["hello"])?, 1);
1610 assert_eq!(insert_stmt.execute(["goodbye"])?, 1);
1611 assert_eq!(insert_stmt.execute([types::Null])?, 1);
1612
1613 let mut update_stmt = db.prepare("UPDATE foo SET x=?1 WHERE x<?2")?;
1614 assert_eq!(update_stmt.execute([3i32, 3i32])?, 2);
1615 assert_eq!(update_stmt.execute([3i32, 3i32])?, 0);
1616 assert_eq!(update_stmt.execute([8i32, 8i32])?, 3);
1617 Ok(())
1618 }
1619
1620 #[test]
1621 fn test_prepare_query() -> Result<()> {
1622 let db = Connection::open_in_memory()?;
1623 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1624
1625 let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?1)")?;
1626 assert_eq!(insert_stmt.execute([1i32])?, 1);
1627 assert_eq!(insert_stmt.execute([2i32])?, 1);
1628 assert_eq!(insert_stmt.execute([3i32])?, 1);
1629
1630 let mut query = db.prepare("SELECT x FROM foo WHERE x < ?1 ORDER BY x DESC")?;
1631 {
1632 let mut rows = query.query([4i32])?;
1633 let mut v = Vec::<i32>::new();
1634
1635 while let Some(row) = rows.next()? {
1636 v.push(row.get(0)?);
1637 }
1638
1639 assert_eq!(v, [3i32, 2, 1]);
1640 }
1641
1642 {
1643 let mut rows = query.query([3i32])?;
1644 let mut v = Vec::<i32>::new();
1645
1646 while let Some(row) = rows.next()? {
1647 v.push(row.get(0)?);
1648 }
1649
1650 assert_eq!(v, [2i32, 1]);
1651 }
1652 Ok(())
1653 }
1654
1655 #[test]
1656 fn test_query_map() -> Result<()> {
1657 let db = Connection::open_in_memory()?;
1658 let sql = "BEGIN;
1659 CREATE TABLE foo(x INTEGER, y TEXT);
1660 INSERT INTO foo VALUES(4, \"hello\");
1661 INSERT INTO foo VALUES(3, \", \");
1662 INSERT INTO foo VALUES(2, \"world\");
1663 INSERT INTO foo VALUES(1, \"!\");
1664 END;";
1665 db.execute_batch(sql)?;
1666
1667 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1668 let results: Result<Vec<String>> = query.query([])?.map(|row| row.get(1)).collect();
1669
1670 assert_eq!(results?.concat(), "hello, world!");
1671 Ok(())
1672 }
1673
1674 #[test]
1675 fn test_query_row() -> Result<()> {
1676 let db = Connection::open_in_memory()?;
1677 let sql = "BEGIN;
1678 CREATE TABLE foo(x INTEGER);
1679 INSERT INTO foo VALUES(1);
1680 INSERT INTO foo VALUES(2);
1681 INSERT INTO foo VALUES(3);
1682 INSERT INTO foo VALUES(4);
1683 END;";
1684 db.execute_batch(sql)?;
1685
1686 assert_eq!(10i64, db.one_column::<i64>("SELECT SUM(x) FROM foo")?);
1687
1688 let result: Result<i64> = db.one_column("SELECT x FROM foo WHERE x > 5");
1689 match result.unwrap_err() {
1690 Error::QueryReturnedNoRows => (),
1691 err => panic!("Unexpected error {err}"),
1692 }
1693
1694 let bad_query_result = db.query_row("NOT A PROPER QUERY; test123", [], |_| Ok(()));
1695
1696 bad_query_result.unwrap_err();
1697 Ok(())
1698 }
1699
1700 #[test]
1701 fn test_optional() -> Result<()> {
1702 let db = Connection::open_in_memory()?;
1703
1704 let result: Result<i64> = db.one_column("SELECT 1 WHERE 0 <> 0");
1705 let result = result.optional();
1706 match result? {
1707 None => (),
1708 _ => panic!("Unexpected result"),
1709 }
1710
1711 let result: Result<i64> = db.one_column("SELECT 1 WHERE 0 == 0");
1712 let result = result.optional();
1713 match result? {
1714 Some(1) => (),
1715 _ => panic!("Unexpected result"),
1716 }
1717
1718 let bad_query_result: Result<i64> = db.one_column("NOT A PROPER QUERY");
1719 let bad_query_result = bad_query_result.optional();
1720 bad_query_result.unwrap_err();
1721 Ok(())
1722 }
1723
1724 #[test]
1725 fn test_pragma_query_row() -> Result<()> {
1726 let db = Connection::open_in_memory()?;
1727 assert_eq!("memory", db.one_column::<String>("PRAGMA journal_mode")?);
1728 let mode = db.one_column::<String>("PRAGMA journal_mode=off")?;
1729 if cfg!(feature = "bundled") {
1730 assert_eq!(mode, "off");
1731 } else {
1732 assert!(mode == "memory" || mode == "off", "Got mode {mode:?}");
1744 }
1745
1746 Ok(())
1747 }
1748
1749 #[test]
1750 fn test_prepare_failures() -> Result<()> {
1751 let db = Connection::open_in_memory()?;
1752 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1753
1754 let err = db.prepare("SELECT * FROM does_not_exist").unwrap_err();
1755 assert!(format!("{err}").contains("does_not_exist"));
1756 Ok(())
1757 }
1758
1759 #[test]
1760 fn test_last_insert_rowid() -> Result<()> {
1761 let db = Connection::open_in_memory()?;
1762 db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)")?;
1763 db.execute_batch("INSERT INTO foo DEFAULT VALUES")?;
1764
1765 assert_eq!(db.last_insert_rowid(), 1);
1766
1767 let mut stmt = db.prepare("INSERT INTO foo DEFAULT VALUES")?;
1768 for _ in 0i32..9 {
1769 stmt.execute([])?;
1770 }
1771 assert_eq!(db.last_insert_rowid(), 10);
1772 Ok(())
1773 }
1774
1775 #[test]
1776 fn test_total_changes() -> Result<()> {
1777 let db = Connection::open_in_memory()?;
1778 let sql = "CREATE TABLE foo(x INTEGER PRIMARY KEY, value TEXT default '' NOT NULL,
1779 desc TEXT default '');
1780 CREATE VIEW foo_bar AS SELECT x, desc FROM foo WHERE value = 'bar';
1781 CREATE TRIGGER INSERT_FOOBAR
1782 INSTEAD OF INSERT
1783 ON foo_bar
1784 BEGIN
1785 INSERT INTO foo VALUES(new.x, 'bar', new.desc);
1786 END;";
1787 db.execute_batch(sql)?;
1788 let total_changes_before = db.total_changes();
1789 let changes = db
1790 .prepare("INSERT INTO foo_bar VALUES(null, 'baz');")?
1791 .execute([])?;
1792 let total_changes_after = db.total_changes();
1793 assert_eq!(changes, 0);
1794 assert_eq!(total_changes_after - total_changes_before, 1);
1795 Ok(())
1796 }
1797
1798 #[test]
1799 fn test_is_autocommit() -> Result<()> {
1800 let db = Connection::open_in_memory()?;
1801 assert!(
1802 db.is_autocommit(),
1803 "autocommit expected to be active by default"
1804 );
1805 Ok(())
1806 }
1807
1808 #[test]
1809 fn test_is_busy() -> Result<()> {
1810 let db = Connection::open_in_memory()?;
1811 assert!(!db.is_busy());
1812 let mut stmt = db.prepare("PRAGMA schema_version")?;
1813 assert!(!db.is_busy());
1814 {
1815 let mut rows = stmt.query([])?;
1816 assert!(!db.is_busy());
1817 let row = rows.next()?;
1818 assert!(db.is_busy());
1819 assert!(row.is_some());
1820 }
1821 assert!(!db.is_busy());
1822 Ok(())
1823 }
1824
1825 #[test]
1826 fn test_statement_debugging() -> Result<()> {
1827 let db = Connection::open_in_memory()?;
1828 let query = "SELECT 12345";
1829 let stmt = db.prepare(query)?;
1830
1831 assert!(format!("{stmt:?}").contains(query));
1832 Ok(())
1833 }
1834
1835 #[test]
1836 fn test_notnull_constraint_error() -> Result<()> {
1837 let db = Connection::open_in_memory()?;
1838 db.execute_batch("CREATE TABLE foo(x NOT NULL)")?;
1839
1840 let result = db.execute("INSERT INTO foo (x) VALUES (NULL)", []);
1841
1842 match result.unwrap_err() {
1843 Error::SqliteFailure(err, _) => {
1844 assert_eq!(err.code, ErrorCode::ConstraintViolation);
1845 assert_eq!(err.extended_code, ffi::SQLITE_CONSTRAINT_NOTNULL);
1846 }
1847 err => panic!("Unexpected error {err}"),
1848 }
1849 Ok(())
1850 }
1851
1852 #[test]
1853 fn test_version_string() {
1854 let n = version_number();
1855 let major = n / 1_000_000;
1856 let minor = (n % 1_000_000) / 1_000;
1857 let patch = n % 1_000;
1858
1859 assert!(version().contains(&format!("{major}.{minor}.{patch}")));
1860 }
1861
1862 #[test]
1863 #[cfg(feature = "functions")]
1864 fn test_interrupt() -> Result<()> {
1865 let db = Connection::open_in_memory()?;
1866
1867 let interrupt_handle = db.get_interrupt_handle();
1868
1869 db.create_scalar_function(
1870 "interrupt",
1871 0,
1872 functions::FunctionFlags::default(),
1873 move |_| {
1874 interrupt_handle.interrupt();
1875 Ok(0)
1876 },
1877 )?;
1878
1879 let mut stmt =
1880 db.prepare("SELECT interrupt() FROM (SELECT 1 UNION SELECT 2 UNION SELECT 3)")?;
1881
1882 let result: Result<Vec<i32>> = stmt.query([])?.map(|r| r.get(0)).collect();
1883
1884 assert_eq!(
1885 result.unwrap_err().sqlite_error_code(),
1886 Some(ErrorCode::OperationInterrupted)
1887 );
1888 Ok(())
1889 }
1890
1891 #[test]
1892 fn test_interrupt_close() {
1893 let db = checked_memory_handle();
1894 let handle = db.get_interrupt_handle();
1895 handle.interrupt();
1896 db.close().unwrap();
1897 handle.interrupt();
1898
1899 let db_guard = handle.db_lock.lock().unwrap();
1901 assert!(db_guard.is_null());
1902 }
1906
1907 #[test]
1908 fn test_get_raw() -> Result<()> {
1909 let db = Connection::open_in_memory()?;
1910 db.execute_batch("CREATE TABLE foo(i, x);")?;
1911 let vals = ["foobar", "1234", "qwerty"];
1912 let mut insert_stmt = db.prepare("INSERT INTO foo(i, x) VALUES(?1, ?2)")?;
1913 for (i, v) in vals.iter().enumerate() {
1914 let i_to_insert = i as i64;
1915 assert_eq!(insert_stmt.execute(params![i_to_insert, v])?, 1);
1916 }
1917
1918 let mut query = db.prepare("SELECT i, x FROM foo")?;
1919 let mut rows = query.query([])?;
1920
1921 while let Some(row) = rows.next()? {
1922 let i = row.get_ref(0)?.as_i64()?;
1923 let expect = vals[i as usize];
1924 let x = row.get_ref("x")?.as_str()?;
1925 assert_eq!(x, expect);
1926 }
1927
1928 let mut query = db.prepare("SELECT x FROM foo")?;
1929 let rows = query.query_map([], |row| {
1930 let x = row.get_ref(0)?.as_str()?; Ok(x[..].to_owned())
1932 })?;
1933
1934 for (i, row) in rows.enumerate() {
1935 assert_eq!(row?, vals[i]);
1936 }
1937 Ok(())
1938 }
1939
1940 #[test]
1941 fn test_from_handle() -> Result<()> {
1942 let db = Connection::open_in_memory()?;
1943 let handle = unsafe { db.handle() };
1944 {
1945 let db = unsafe { Connection::from_handle(handle) }?;
1946 db.execute_batch("PRAGMA VACUUM")?;
1947 }
1948 db.close().unwrap();
1949 Ok(())
1950 }
1951
1952 #[test]
1953 fn test_from_handle_owned() -> Result<()> {
1954 let mut handle: *mut ffi::sqlite3 = std::ptr::null_mut();
1955 let r = unsafe { ffi::sqlite3_open(c":memory:".as_ptr(), &mut handle) };
1956 assert_eq!(r, ffi::SQLITE_OK);
1957 let db = unsafe { Connection::from_handle_owned(handle) }?;
1958 db.execute_batch("PRAGMA VACUUM")?;
1959 Ok(())
1960 }
1961
1962 mod query_and_then_tests {
1963
1964 use super::*;
1965
1966 #[derive(Debug)]
1967 enum CustomError {
1968 SomeError,
1969 Sqlite(Error),
1970 }
1971
1972 impl fmt::Display for CustomError {
1973 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1974 match *self {
1975 Self::SomeError => write!(f, "my custom error"),
1976 Self::Sqlite(ref se) => write!(f, "my custom error: {se}"),
1977 }
1978 }
1979 }
1980
1981 impl StdError for CustomError {
1982 fn description(&self) -> &str {
1983 "my custom error"
1984 }
1985
1986 fn cause(&self) -> Option<&dyn StdError> {
1987 match *self {
1988 Self::SomeError => None,
1989 Self::Sqlite(ref se) => Some(se),
1990 }
1991 }
1992 }
1993
1994 impl From<Error> for CustomError {
1995 fn from(se: Error) -> Self {
1996 Self::Sqlite(se)
1997 }
1998 }
1999
2000 type CustomResult<T> = Result<T, CustomError>;
2001
2002 #[test]
2003 fn test_query_and_then() -> 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 results: Result<Vec<String>> =
2016 query.query_and_then([], |row| row.get(1))?.collect();
2017
2018 assert_eq!(results?.concat(), "hello, world!");
2019 Ok(())
2020 }
2021
2022 #[test]
2023 fn test_query_and_then_fails() -> Result<()> {
2024 let db = Connection::open_in_memory()?;
2025 let sql = "BEGIN;
2026 CREATE TABLE foo(x INTEGER, y TEXT);
2027 INSERT INTO foo VALUES(4, \"hello\");
2028 INSERT INTO foo VALUES(3, \", \");
2029 INSERT INTO foo VALUES(2, \"world\");
2030 INSERT INTO foo VALUES(1, \"!\");
2031 END;";
2032 db.execute_batch(sql)?;
2033
2034 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
2035 let bad_type: Result<Vec<f64>> = query.query_and_then([], |row| row.get(1))?.collect();
2036
2037 match bad_type.unwrap_err() {
2038 Error::InvalidColumnType(..) => (),
2039 err => panic!("Unexpected error {err}"),
2040 }
2041
2042 let bad_idx: Result<Vec<String>> =
2043 query.query_and_then([], |row| row.get(3))?.collect();
2044
2045 match bad_idx.unwrap_err() {
2046 Error::InvalidColumnIndex(_) => (),
2047 err => panic!("Unexpected error {err}"),
2048 }
2049 Ok(())
2050 }
2051
2052 #[test]
2053 fn test_query_and_then_custom_error() -> CustomResult<()> {
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 results: CustomResult<Vec<String>> = query
2066 .query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite))?
2067 .collect();
2068
2069 assert_eq!(results?.concat(), "hello, world!");
2070 Ok(())
2071 }
2072
2073 #[test]
2074 fn test_query_and_then_custom_error_fails() -> Result<()> {
2075 let db = Connection::open_in_memory()?;
2076 let sql = "BEGIN;
2077 CREATE TABLE foo(x INTEGER, y TEXT);
2078 INSERT INTO foo VALUES(4, \"hello\");
2079 INSERT INTO foo VALUES(3, \", \");
2080 INSERT INTO foo VALUES(2, \"world\");
2081 INSERT INTO foo VALUES(1, \"!\");
2082 END;";
2083 db.execute_batch(sql)?;
2084
2085 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
2086 let bad_type: CustomResult<Vec<f64>> = query
2087 .query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite))?
2088 .collect();
2089
2090 match bad_type.unwrap_err() {
2091 CustomError::Sqlite(Error::InvalidColumnType(..)) => (),
2092 err => panic!("Unexpected error {err}"),
2093 }
2094
2095 let bad_idx: CustomResult<Vec<String>> = query
2096 .query_and_then([], |row| row.get(3).map_err(CustomError::Sqlite))?
2097 .collect();
2098
2099 match bad_idx.unwrap_err() {
2100 CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
2101 err => panic!("Unexpected error {err}"),
2102 }
2103
2104 let non_sqlite_err: CustomResult<Vec<String>> = query
2105 .query_and_then([], |_| Err(CustomError::SomeError))?
2106 .collect();
2107
2108 match non_sqlite_err.unwrap_err() {
2109 CustomError::SomeError => (),
2110 err => panic!("Unexpected error {err}"),
2111 }
2112 Ok(())
2113 }
2114
2115 #[test]
2116 fn test_query_row_and_then_custom_error() -> CustomResult<()> {
2117 let db = Connection::open_in_memory()?;
2118 let sql = "BEGIN;
2119 CREATE TABLE foo(x INTEGER, y TEXT);
2120 INSERT INTO foo VALUES(4, \"hello\");
2121 END;";
2122 db.execute_batch(sql)?;
2123
2124 let query = "SELECT x, y FROM foo ORDER BY x DESC";
2125 let results: CustomResult<String> =
2126 db.query_row_and_then(query, [], |row| row.get(1).map_err(CustomError::Sqlite));
2127
2128 assert_eq!(results?, "hello");
2129 Ok(())
2130 }
2131
2132 #[test]
2133 fn test_query_row_and_then_custom_error_fails() -> Result<()> {
2134 let db = Connection::open_in_memory()?;
2135 let sql = "BEGIN;
2136 CREATE TABLE foo(x INTEGER, y TEXT);
2137 INSERT INTO foo VALUES(4, \"hello\");
2138 END;";
2139 db.execute_batch(sql)?;
2140
2141 let query = "SELECT x, y FROM foo ORDER BY x DESC";
2142 let bad_type: CustomResult<f64> =
2143 db.query_row_and_then(query, [], |row| row.get(1).map_err(CustomError::Sqlite));
2144
2145 match bad_type.unwrap_err() {
2146 CustomError::Sqlite(Error::InvalidColumnType(..)) => (),
2147 err => panic!("Unexpected error {err}"),
2148 }
2149
2150 let bad_idx: CustomResult<String> =
2151 db.query_row_and_then(query, [], |row| row.get(3).map_err(CustomError::Sqlite));
2152
2153 match bad_idx.unwrap_err() {
2154 CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
2155 err => panic!("Unexpected error {err}"),
2156 }
2157
2158 let non_sqlite_err: CustomResult<String> =
2159 db.query_row_and_then(query, [], |_| Err(CustomError::SomeError));
2160
2161 match non_sqlite_err.unwrap_err() {
2162 CustomError::SomeError => (),
2163 err => panic!("Unexpected error {err}"),
2164 }
2165 Ok(())
2166 }
2167 }
2168
2169 #[test]
2170 fn test_dynamic() -> Result<()> {
2171 let db = Connection::open_in_memory()?;
2172 let sql = "BEGIN;
2173 CREATE TABLE foo(x INTEGER, y TEXT);
2174 INSERT INTO foo VALUES(4, \"hello\");
2175 END;";
2176 db.execute_batch(sql)?;
2177
2178 db.query_row("SELECT * FROM foo", [], |r| {
2179 assert_eq!(2, r.as_ref().column_count());
2180 Ok(())
2181 })
2182 }
2183 #[test]
2184 fn test_dyn_box() -> Result<()> {
2185 let db = Connection::open_in_memory()?;
2186 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
2187 let b: Box<dyn ToSql> = Box::new(5);
2188 db.execute("INSERT INTO foo VALUES(?1)", [b])?;
2189 db.query_row("SELECT x FROM foo", [], |r| {
2190 assert_eq!(5, r.get_unwrap::<_, i32>(0));
2191 Ok(())
2192 })
2193 }
2194
2195 #[test]
2196 fn test_params() -> Result<()> {
2197 let db = Connection::open_in_memory()?;
2198 db.query_row(
2199 "SELECT
2200 ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10,
2201 ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19, ?20,
2202 ?21, ?22, ?23, ?24, ?25, ?26, ?27, ?28, ?29, ?30,
2203 ?31, ?32, ?33, ?34;",
2204 params![
2205 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,
2206 1, 1, 1, 1, 1, 1,
2207 ],
2208 |r| {
2209 assert_eq!(1, r.get_unwrap::<_, i32>(0));
2210 Ok(())
2211 },
2212 )
2213 }
2214
2215 #[test]
2216 #[cfg(not(feature = "extra_check"))]
2217 fn test_alter_table() -> Result<()> {
2218 let db = Connection::open_in_memory()?;
2219 db.execute_batch("CREATE TABLE x(t);")?;
2220 db.execute("ALTER TABLE x RENAME TO y;", [])?;
2222 Ok(())
2223 }
2224
2225 #[test]
2226 fn test_batch() -> Result<()> {
2227 let db = Connection::open_in_memory()?;
2228 let sql = r"
2229 CREATE TABLE tbl1 (col);
2230 CREATE TABLE tbl2 (col);
2231 ";
2232 let mut batch = Batch::new(&db, sql);
2233 while let Some(mut stmt) = batch.next()? {
2234 stmt.execute([])?;
2235 }
2236 Ok(())
2237 }
2238
2239 #[test]
2240 fn test_invalid_batch() -> Result<()> {
2241 let db = Connection::open_in_memory()?;
2242 let sql = r"
2243 PRAGMA test1;
2244 PRAGMA test2=?;
2245 PRAGMA test3;
2246 ";
2247 let mut batch = Batch::new(&db, sql);
2248 assert!(batch.next().is_ok());
2249 assert!(batch.next().is_err());
2250 assert!(batch.next().is_err());
2251 assert!(Batch::new(&db, sql).count().is_err());
2252 Ok(())
2253 }
2254
2255 #[test]
2256 #[cfg(feature = "modern_sqlite")]
2257 fn test_returning() -> Result<()> {
2258 let db = Connection::open_in_memory()?;
2259 db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)")?;
2260 let row_id = db.one_column::<i64>("INSERT INTO foo DEFAULT VALUES RETURNING ROWID")?;
2261 assert_eq!(row_id, 1);
2262 Ok(())
2263 }
2264
2265 #[test]
2266 fn test_cache_flush() -> Result<()> {
2267 let db = Connection::open_in_memory()?;
2268 db.cache_flush()
2269 }
2270
2271 #[test]
2272 fn db_readonly() -> Result<()> {
2273 let db = Connection::open_in_memory()?;
2274 assert!(!db.is_readonly(MAIN_DB)?);
2275 Ok(())
2276 }
2277
2278 #[test]
2279 #[cfg(feature = "rusqlite-macros")]
2280 fn prepare_and_bind() -> Result<()> {
2281 let db = Connection::open_in_memory()?;
2282 let name = "Lisa";
2283 let age = 8;
2284 let mut stmt = prepare_and_bind!(db, "SELECT $name, $age;");
2285 let (v1, v2) = stmt
2286 .raw_query()
2287 .next()
2288 .and_then(|o| o.ok_or(Error::QueryReturnedNoRows))
2289 .and_then(|r| Ok((r.get::<_, String>(0)?, r.get::<_, i64>(1)?)))?;
2290 assert_eq!((v1.as_str(), v2), (name, age));
2291 Ok(())
2292 }
2293
2294 #[test]
2295 #[cfg(feature = "modern_sqlite")]
2296 fn test_db_name() -> Result<()> {
2297 let db = Connection::open_in_memory()?;
2298 assert_eq!(db.db_name(0)?, "main");
2299 assert_eq!(db.db_name(1)?, "temp");
2300 assert_eq!(db.db_name(2), Err(Error::InvalidDatabaseIndex(2)));
2301 db.execute_batch("ATTACH DATABASE ':memory:' AS xyz;")?;
2302 assert_eq!(db.db_name(2)?, "xyz");
2303 Ok(())
2304 }
2305
2306 #[test]
2307 #[cfg(feature = "modern_sqlite")]
2308 fn test_is_interrupted() -> Result<()> {
2309 let db = Connection::open_in_memory()?;
2310 assert!(!db.is_interrupted());
2311 db.get_interrupt_handle().interrupt();
2312 assert!(db.is_interrupted());
2313 Ok(())
2314 }
2315
2316 #[test]
2317 fn release_memory() -> Result<()> {
2318 let db = Connection::open_in_memory()?;
2319 db.release_memory()
2320 }
2321}