1#![warn(missing_docs)]
55#![cfg_attr(docsrs, feature(doc_cfg))]
56
57pub use fallible_iterator;
58pub use fallible_streaming_iterator;
59
60#[cfg(not(all(
61 target_family = "wasm",
62 target_os = "unknown",
63 any(test, feature = "ffi-sqlite-wasm-rs")
64)))]
65pub use libsqlite3_sys as ffi;
66#[cfg(all(
67 target_family = "wasm",
68 target_os = "unknown",
69 any(test, feature = "ffi-sqlite-wasm-rs")
70))]
71pub use sqlite_wasm_rs as ffi;
72
73use std::cell::RefCell;
74use std::default::Default;
75use std::ffi::{c_char, c_int, c_uint, CStr, CString};
76use std::fmt;
77
78use std::path::Path;
79use std::result;
80use std::str;
81use std::sync::{Arc, Mutex};
82
83#[cfg(feature = "cache")]
84use crate::cache::StatementCache;
85use crate::inner_connection::InnerConnection;
86use crate::raw_statement::RawStatement;
87use crate::types::ValueRef;
88
89pub use crate::bind::BindIndex;
90#[cfg(feature = "cache")]
91pub use crate::cache::CachedStatement;
92#[cfg(feature = "column_decltype")]
93pub use crate::column::Column;
94#[cfg(feature = "column_metadata")]
95pub use crate::column::ColumnMetadata;
96pub use crate::error::{to_sqlite_error, Error};
97pub use crate::ffi::ErrorCode;
98#[cfg(feature = "load_extension")]
99pub use crate::load_extension_guard::LoadExtensionGuard;
100pub use crate::params::{params_from_iter, Params, ParamsFromIter};
101pub use crate::row::{AndThenRows, Map, MappedRows, Row, RowIndex, Rows};
102pub use crate::statement::{Statement, StatementStatus};
103#[cfg(feature = "modern_sqlite")]
104pub use crate::transaction::TransactionState;
105pub use crate::transaction::{DropBehavior, Savepoint, Transaction, TransactionBehavior};
106pub use crate::types::ToSql;
107pub use crate::util::Name;
108pub use crate::version::*;
109#[cfg(feature = "rusqlite-macros")]
110#[doc(hidden)]
111pub use rusqlite_macros::__bind;
112
113#[macro_use]
114mod error;
115
116#[cfg(not(feature = "loadable_extension"))]
117pub mod auto_extension;
118#[cfg(feature = "backup")]
119pub mod backup;
120mod bind;
121#[cfg(feature = "blob")]
122pub mod blob;
123mod busy;
124#[cfg(feature = "cache")]
125mod cache;
126#[cfg(feature = "collation")]
127mod collation;
128mod column;
129pub mod config;
130#[cfg(any(feature = "functions", feature = "vtab"))]
131mod context;
132#[cfg(feature = "functions")]
133pub mod functions;
134#[cfg(feature = "hooks")]
135pub mod hooks;
136mod inner_connection;
137#[cfg(feature = "limits")]
138pub mod limits;
139#[cfg(feature = "load_extension")]
140mod load_extension_guard;
141mod params;
142mod pragma;
143mod raw_statement;
144mod row;
145#[cfg(feature = "serialize")]
146pub mod serialize;
147#[cfg(feature = "session")]
148pub mod session;
149mod statement;
150#[cfg(feature = "trace")]
151pub mod trace;
152mod transaction;
153pub mod types;
154#[cfg(feature = "unlock_notify")]
155mod unlock_notify;
156mod version;
157#[cfg(feature = "vtab")]
158pub mod vtab;
159
160pub(crate) mod util;
161
162#[cfg(all(feature = "loadable_extension", feature = "load_extension"))]
164compile_error!("feature \"loadable_extension\" and feature \"load_extension\" cannot be enabled at the same time");
165
166#[cfg(feature = "cache")]
168const STATEMENT_CACHE_DEFAULT_CAPACITY: usize = 16;
169
170#[macro_export]
193macro_rules! params {
194 () => {
195 &[] as &[&dyn $crate::ToSql]
196 };
197 ($($param:expr),+ $(,)?) => {
198 &[$(&$param as &dyn $crate::ToSql),+] as &[&dyn $crate::ToSql]
199 };
200}
201
202#[macro_export]
230macro_rules! named_params {
231 () => {
232 &[] as &[(&str, &dyn $crate::ToSql)]
233 };
234 ($($param_name:literal: $param_val:expr),+ $(,)?) => {
237 &[$(($param_name, &$param_val as &dyn $crate::ToSql)),+] as &[(&str, &dyn $crate::ToSql)]
238 };
239}
240
241#[cfg(feature = "rusqlite-macros")]
260#[macro_export]
261macro_rules! prepare_and_bind {
262 ($conn:expr, $sql:literal) => {{
263 let mut stmt = $conn.prepare($sql)?;
264 $crate::__bind!(stmt $sql);
265 stmt
266 }};
267}
268
269#[cfg(feature = "rusqlite-macros")]
275#[macro_export]
276macro_rules! prepare_cached_and_bind {
277 ($conn:expr, $sql:literal) => {{
278 let mut stmt = $conn.prepare_cached($sql)?;
279 $crate::__bind!(stmt $sql);
280 stmt
281 }};
282}
283
284pub type Result<T, E = Error> = result::Result<T, E>;
286
287pub trait OptionalExtension<T> {
289 fn optional(self) -> Result<Option<T>>;
295}
296
297impl<T> OptionalExtension<T> for Result<T> {
298 fn optional(self) -> Result<Option<T>> {
299 match self {
300 Ok(value) => Ok(Some(value)),
301 Err(Error::QueryReturnedNoRows) => Ok(None),
302 Err(e) => Err(e),
303 }
304 }
305}
306
307unsafe fn errmsg_to_string(errmsg: *const c_char) -> String {
308 CStr::from_ptr(errmsg).to_string_lossy().into_owned()
309}
310
311#[cfg(any(feature = "functions", feature = "vtab", test))]
312fn str_to_cstring(s: &str) -> Result<util::SmallCString> {
313 Ok(util::SmallCString::new(s)?)
314}
315
316fn str_for_sqlite(
322 s: &[u8],
323) -> (
324 *const c_char,
325 ffi::sqlite3_uint64,
326 ffi::sqlite3_destructor_type,
327) {
328 let len = s.len();
329 let (ptr, dtor_info) = if len != 0 {
330 (s.as_ptr().cast::<c_char>(), ffi::SQLITE_TRANSIENT())
331 } else {
332 ("".as_ptr().cast::<c_char>(), ffi::SQLITE_STATIC())
334 };
335 (ptr, len as ffi::sqlite3_uint64, dtor_info)
336}
337
338fn path_to_cstring(p: &Path) -> Result<CString> {
339 cfg_select! {
340 unix => {
341 use std::os::unix::ffi::OsStrExt as _;
342 Ok(CString::new(p.as_os_str().as_bytes())?)
343 }
344 _ => {
345 let s = p.to_str().ok_or_else(|| Error::InvalidPath(p.to_owned()))?;
346 Ok(CString::new(s)?)
347 }
348 }
349}
350
351pub const MAIN_DB: &CStr = c"main";
353pub const TEMP_DB: &CStr = c"temp";
355
356pub struct Connection {
358 db: RefCell<InnerConnection>,
359 #[cfg(feature = "cache")]
360 cache: StatementCache,
361 transaction_behavior: TransactionBehavior,
362}
363
364unsafe impl Send for Connection {}
365
366impl Drop for Connection {
367 #[inline]
368 fn drop(&mut self) {
369 #[cfg(feature = "cache")]
370 self.flush_prepared_statement_cache();
371 }
372}
373
374impl Connection {
375 #[inline]
437 pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
438 let flags = OpenFlags::default();
439 Self::open_with_flags(path, flags)
440 }
441
442 #[inline]
448 pub fn open_in_memory() -> Result<Self> {
449 let flags = OpenFlags::default();
450 Self::open_in_memory_with_flags(flags)
451 }
452
453 #[inline]
463 pub fn open_with_flags<P: AsRef<Path>>(path: P, flags: OpenFlags) -> Result<Self> {
464 let c_path = path_to_cstring(path.as_ref())?;
465 InnerConnection::open_with_flags(&c_path, flags, None).map(|db| Self {
466 db: RefCell::new(db),
467 #[cfg(feature = "cache")]
468 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
469 transaction_behavior: TransactionBehavior::Deferred,
470 })
471 }
472
473 #[inline]
484 pub fn open_with_flags_and_vfs<P: AsRef<Path>, V: Name>(
485 path: P,
486 flags: OpenFlags,
487 vfs: V,
488 ) -> Result<Self> {
489 let c_path = path_to_cstring(path.as_ref())?;
490 let c_vfs = vfs.as_cstr()?;
491 InnerConnection::open_with_flags(&c_path, flags, Some(&c_vfs)).map(|db| Self {
492 db: RefCell::new(db),
493 #[cfg(feature = "cache")]
494 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
495 transaction_behavior: TransactionBehavior::Deferred,
496 })
497 }
498
499 #[inline]
508 pub fn open_in_memory_with_flags(flags: OpenFlags) -> Result<Self> {
509 Self::open_with_flags(":memory:", flags)
510 }
511
512 #[inline]
523 pub fn open_in_memory_with_flags_and_vfs<V: Name>(flags: OpenFlags, vfs: V) -> Result<Self> {
524 Self::open_with_flags_and_vfs(":memory:", flags, vfs)
525 }
526
527 pub fn execute_batch(&self, sql: &str) -> Result<()> {
549 let mut sql = sql;
550 while !sql.is_empty() {
551 let (stmt, tail) = self
552 .db
553 .borrow_mut()
554 .prepare(self, sql, PrepFlags::default())?;
555 if !stmt.stmt.is_null() && stmt.step()? {
556 if false {
558 return Err(Error::ExecuteReturnedResults);
559 }
560 }
561 if tail == 0 || tail >= sql.len() {
562 break;
563 }
564 sql = &sql[tail..];
565 }
566 Ok(())
567 }
568
569 #[inline]
620 pub fn execute<P: Params>(&self, sql: &str, params: P) -> Result<usize> {
621 self.prepare(sql).and_then(|mut stmt| stmt.execute(params))
622 }
623
624 #[inline]
632 pub fn path(&self) -> Option<&str> {
633 unsafe { inner_connection::db_filename(std::marker::PhantomData, self.handle(), MAIN_DB) }
634 }
635
636 #[inline]
641 pub fn release_memory(&self) -> Result<()> {
642 self.db.borrow_mut().release_memory()
643 }
644
645 #[inline]
650 pub fn last_insert_rowid(&self) -> i64 {
651 self.db.borrow_mut().last_insert_rowid()
652 }
653
654 #[inline]
682 pub fn query_row<T, P, F>(&self, sql: &str, params: P, f: F) -> Result<T>
683 where
684 P: Params,
685 F: FnOnce(&Row<'_>) -> Result<T>,
686 {
687 let mut stmt = self.prepare(sql)?;
688 stmt.query_row(params, f)
689 }
690
691 pub fn query_one<T, P, F>(&self, sql: &str, params: P, f: F) -> Result<T>
706 where
707 P: Params,
708 F: FnOnce(&Row<'_>) -> Result<T>,
709 {
710 let mut stmt = self.prepare(sql)?;
711 stmt.query_one(params, f)
712 }
713
714 #[cfg(test)]
716 pub(crate) fn one_column<T, P>(&self, sql: &str, params: P) -> Result<T>
717 where
718 T: types::FromSql,
719 P: Params,
720 {
721 self.query_one(sql, params, |r| r.get(0))
722 }
723
724 #[inline]
750 pub fn query_row_and_then<T, E, P, F>(&self, sql: &str, params: P, f: F) -> Result<T, E>
751 where
752 P: Params,
753 F: FnOnce(&Row<'_>) -> Result<T, E>,
754 E: From<Error>,
755 {
756 let mut stmt = self.prepare(sql)?;
757 let mut rows = stmt.query(params)?;
758
759 rows.get_expected_row().map_err(E::from).and_then(f)
760 }
761
762 #[inline]
781 pub fn prepare(&self, sql: &str) -> Result<Statement<'_>> {
782 self.prepare_with_flags(sql, PrepFlags::default())
783 }
784
785 #[inline]
792 pub fn prepare_with_flags(&self, sql: &str, flags: PrepFlags) -> Result<Statement<'_>> {
793 let (stmt, tail) = self.db.borrow_mut().prepare(self, sql, flags)?;
794 if tail != 0 && !self.prepare(&sql[tail..])?.stmt.is_null() {
795 Err(Error::MultipleStatement)
796 } else {
797 Ok(stmt)
798 }
799 }
800
801 #[expect(clippy::result_large_err)]
811 #[inline]
812 pub fn close(self) -> Result<(), (Self, Error)> {
813 #[cfg(feature = "cache")]
814 self.flush_prepared_statement_cache();
815 let r = self.db.borrow_mut().close();
816 r.map_err(move |err| (self, err))
817 }
818
819 #[cfg(feature = "load_extension")]
872 #[inline]
873 pub unsafe fn load_extension_enable(&self) -> Result<()> {
874 self.db.borrow_mut().enable_load_extension(1)
875 }
876
877 #[cfg(feature = "load_extension")]
885 #[inline]
886 pub fn load_extension_disable(&self) -> Result<()> {
887 unsafe { self.db.borrow_mut().enable_load_extension(0) }
889 }
890
891 #[cfg(feature = "load_extension")]
927 #[inline]
928 pub unsafe fn load_extension<P: AsRef<Path>, N: Name>(
929 &self,
930 dylib_path: P,
931 entry_point: Option<N>,
932 ) -> Result<()> {
933 self.db
934 .borrow_mut()
935 .load_extension(dylib_path.as_ref(), entry_point)
936 }
937
938 #[inline]
952 pub unsafe fn handle(&self) -> *mut ffi::sqlite3 {
953 self.db.borrow().db()
954 }
955
956 #[inline]
965 pub unsafe fn from_handle(db: *mut ffi::sqlite3) -> Result<Self> {
966 let db = InnerConnection::new(db, false);
967 Ok(Self {
968 db: RefCell::new(db),
969 #[cfg(feature = "cache")]
970 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
971 transaction_behavior: TransactionBehavior::Deferred,
972 })
973 }
974
975 #[cfg(feature = "loadable_extension")]
981 pub unsafe fn extension_init2(
982 db: *mut ffi::sqlite3,
983 pz_err_msg: *mut *mut c_char,
984 p_api: *mut ffi::sqlite3_api_routines,
985 init: fn(Self) -> Result<bool>,
986 ) -> c_int {
987 if p_api.is_null() {
988 return ffi::SQLITE_ERROR;
989 }
990 match ffi::rusqlite_extension_init2(p_api)
991 .map_err(Error::from)
992 .and(Self::from_handle(db))
993 .and_then(init)
994 {
995 Err(err) => to_sqlite_error(&err, pz_err_msg),
996 Ok(true) => ffi::SQLITE_OK_LOAD_PERMANENTLY,
997 _ => ffi::SQLITE_OK,
998 }
999 }
1000
1001 #[inline]
1014 pub unsafe fn from_handle_owned(db: *mut ffi::sqlite3) -> Result<Self> {
1015 let db = InnerConnection::new(db, true);
1016 Ok(Self {
1017 db: RefCell::new(db),
1018 #[cfg(feature = "cache")]
1019 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
1020 transaction_behavior: TransactionBehavior::Deferred,
1021 })
1022 }
1023
1024 #[inline]
1027 pub fn get_interrupt_handle(&self) -> InterruptHandle {
1028 self.db.borrow().get_interrupt_handle()
1029 }
1030
1031 #[inline]
1032 fn decode_result(&self, code: c_int) -> Result<()> {
1033 self.db.borrow().decode_result(code)
1034 }
1035
1036 #[inline]
1042 pub fn changes(&self) -> u64 {
1043 self.db.borrow().changes()
1044 }
1045
1046 #[inline]
1052 pub fn total_changes(&self) -> u64 {
1053 self.db.borrow().total_changes()
1054 }
1055
1056 #[inline]
1059 pub fn is_autocommit(&self) -> bool {
1060 self.db.borrow().is_autocommit()
1061 }
1062
1063 #[inline]
1065 pub fn is_busy(&self) -> bool {
1066 self.db.borrow().is_busy()
1067 }
1068
1069 pub fn cache_flush(&self) -> Result<()> {
1071 self.db.borrow_mut().cache_flush()
1072 }
1073
1074 pub fn is_readonly<N: Name>(&self, db_name: N) -> Result<bool> {
1076 self.db.borrow().db_readonly(db_name)
1077 }
1078
1079 #[cfg(feature = "modern_sqlite")] pub fn db_name(&self, index: usize) -> Result<String> {
1086 unsafe {
1087 let db = self.handle();
1088 let name = ffi::sqlite3_db_name(db, index as c_int);
1089 if name.is_null() {
1090 Err(Error::InvalidDatabaseIndex(index))
1091 } else {
1092 Ok(CStr::from_ptr(name).to_str()?.to_owned())
1093 }
1094 }
1095 }
1096
1097 #[cfg(feature = "modern_sqlite")] pub fn is_interrupted(&self) -> bool {
1100 self.db.borrow().is_interrupted()
1101 }
1102
1103 #[cfg(feature = "modern_sqlite")] pub fn set_errmsg(&self, code: c_int, msg: Option<&std::ffi::CStr>) -> Result<()> {
1106 unsafe { error::set_errmsg(self.handle(), code, msg) }
1107 }
1108}
1109
1110impl fmt::Debug for Connection {
1111 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1112 f.debug_struct("Connection")
1113 .field("path", &self.path())
1114 .finish()
1115 }
1116}
1117
1118#[derive(Debug)]
1143pub struct Batch<'conn, 'sql> {
1144 conn: &'conn Connection,
1145 sql: &'sql str,
1146 tail: usize,
1147}
1148
1149impl<'conn, 'sql> Batch<'conn, 'sql> {
1150 pub fn new(conn: &'conn Connection, sql: &'sql str) -> Self {
1152 Batch { conn, sql, tail: 0 }
1153 }
1154}
1155impl<'conn> fallible_iterator::FallibleIterator for Batch<'conn, '_> {
1156 type Item = Statement<'conn>;
1157 type Error = Error;
1158
1159 fn next(&mut self) -> Result<Option<Statement<'conn>>> {
1163 while self.tail < self.sql.len() {
1164 let sql = &self.sql[self.tail..];
1165 let (next, tail) =
1166 self.conn
1167 .db
1168 .borrow_mut()
1169 .prepare(self.conn, sql, PrepFlags::default())?;
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: c_uint {
1274 const SQLITE_PREPARE_PERSISTENT = 0x01;
1276 const SQLITE_PREPARE_NO_VTAB = 0x04;
1278 const SQLITE_PREPARE_DONT_LOG = 0x10;
1280 const SQLITE_PREPARE_FROM_DDL = 0x20; }
1284}
1285
1286pub struct InterruptHandle {
1288 db_lock: Arc<Mutex<*mut ffi::sqlite3>>,
1289}
1290
1291unsafe impl Send for InterruptHandle {}
1292unsafe impl Sync for InterruptHandle {}
1293
1294impl InterruptHandle {
1295 pub fn interrupt(&self) {
1298 let db_handle = self.db_lock.lock().unwrap();
1299 if !db_handle.is_null() {
1300 unsafe { ffi::sqlite3_interrupt(*db_handle) }
1301 }
1302 }
1303}
1304
1305#[cfg(doctest)]
1306doc_comment::doctest!("../README.md");
1307
1308#[cfg(all(test, not(miri)))]
1309mod test {
1310 #[cfg(all(target_family = "wasm", target_os = "unknown"))]
1311 use wasm_bindgen_test::wasm_bindgen_test as test;
1312
1313 use super::*;
1314 use fallible_iterator::FallibleIterator as _;
1315 use std::error::Error as StdError;
1316 use std::fmt;
1317
1318 #[allow(dead_code)]
1322 #[expect(unconditional_recursion, clippy::extra_unused_type_parameters)]
1323 fn ensure_send<T: Send>() {
1324 ensure_send::<Connection>();
1325 ensure_send::<InterruptHandle>();
1326 }
1327
1328 #[allow(dead_code)]
1329 #[expect(unconditional_recursion, clippy::extra_unused_type_parameters)]
1330 fn ensure_sync<T: Sync>() {
1331 ensure_sync::<InterruptHandle>();
1332 }
1333
1334 fn checked_memory_handle() -> Connection {
1335 Connection::open_in_memory().unwrap()
1336 }
1337
1338 #[cfg_attr(
1339 all(target_family = "wasm", target_os = "unknown"),
1340 ignore = "no filesystem on this platform"
1341 )]
1342 #[test]
1343 fn test_concurrent_transactions_busy_commit() -> Result<()> {
1344 use std::time::Duration;
1345 let tmp = tempfile::tempdir().unwrap();
1346 let path = tmp.path().join("transactions.db3");
1347
1348 Connection::open(&path)?.execute_batch(
1349 "
1350 BEGIN; CREATE TABLE foo(x INTEGER);
1351 INSERT INTO foo VALUES(42); END;",
1352 )?;
1353
1354 let mut db1 = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_WRITE)?;
1355 let mut db2 = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_ONLY)?;
1356
1357 db1.busy_timeout(Duration::from_millis(0))?;
1358 db2.busy_timeout(Duration::from_millis(0))?;
1359
1360 {
1361 let tx1 = db1.transaction()?;
1362 let tx2 = db2.transaction()?;
1363
1364 tx1.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))?;
1366 tx2.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))?;
1367
1368 tx1.execute("INSERT INTO foo VALUES(?1)", [1])?;
1369 let _ = tx2.execute("INSERT INTO foo VALUES(?1)", [2]);
1370
1371 let _ = tx1.commit();
1372 let _ = tx2.commit();
1373 }
1374
1375 let _ = db1
1376 .transaction()
1377 .expect("commit should have closed transaction");
1378 let _ = db2
1379 .transaction()
1380 .expect("commit should have closed transaction");
1381 Ok(())
1382 }
1383
1384 #[cfg_attr(
1385 all(target_family = "wasm", target_os = "unknown"),
1386 ignore = "no filesystem on this platform"
1387 )]
1388 #[test]
1389 fn test_persistence() -> Result<()> {
1390 let temp_dir = tempfile::tempdir().unwrap();
1391 let path = temp_dir.path().join("test.db3");
1392
1393 {
1394 let db = Connection::open(&path)?;
1395 let sql = "BEGIN;
1396 CREATE TABLE foo(x INTEGER);
1397 INSERT INTO foo VALUES(42);
1398 END;";
1399 db.execute_batch(sql)?;
1400 }
1401
1402 let path_string = path.to_str().unwrap();
1403 let db = Connection::open(path_string)?;
1404
1405 assert_eq!(42, db.one_column::<i64, _>("SELECT x FROM foo", [])?);
1406 Ok(())
1407 }
1408
1409 #[test]
1410 fn test_open() {
1411 Connection::open_in_memory().unwrap();
1412
1413 let db = checked_memory_handle();
1414 db.close().unwrap();
1415 }
1416
1417 #[cfg_attr(
1418 all(target_family = "wasm", target_os = "unknown"),
1419 ignore = "no filesystem on this platform"
1420 )]
1421 #[test]
1422 fn test_path() -> Result<()> {
1423 let tmp = tempfile::tempdir().unwrap();
1424 let db = Connection::open("")?;
1425 assert_eq!(Some(""), db.path());
1426 let db = Connection::open_in_memory()?;
1427 assert_eq!(Some(""), db.path());
1428 let db = Connection::open("file:dummy.db?mode=memory&cache=shared")?;
1429 assert_eq!(Some(""), db.path());
1430 let path = tmp.path().join("file.db");
1431 let db = Connection::open(path)?;
1432 assert!(db.path().is_some_and(|p| p.ends_with("file.db")));
1433 Ok(())
1434 }
1435
1436 #[test]
1437 fn test_open_failure() {
1438 let filename = "no_such_file.db";
1439 let result = Connection::open_with_flags(filename, OpenFlags::SQLITE_OPEN_READ_ONLY);
1440 let err = result.unwrap_err();
1441 if let Error::SqliteFailure(e, Some(msg)) = err {
1442 assert_eq!(ErrorCode::CannotOpen, e.code);
1443 assert_eq!(ffi::SQLITE_CANTOPEN, e.extended_code);
1444 assert!(
1445 msg.contains(filename),
1446 "error message '{msg}' does not contain '{filename}'"
1447 );
1448 } else {
1449 panic!("SqliteFailure expected");
1450 }
1451 }
1452
1453 #[cfg(unix)]
1454 #[test]
1455 fn test_invalid_unicode_file_names() -> Result<()> {
1456 use std::ffi::OsStr;
1457 use std::fs::File;
1458 use std::os::unix::ffi::OsStrExt as _;
1459 let temp_dir = tempfile::tempdir().unwrap();
1460
1461 let path = temp_dir.path();
1462 if File::create(path.join(OsStr::from_bytes(&[0xFE]))).is_err() {
1463 return Ok(());
1465 }
1466 let db_path = path.join(OsStr::from_bytes(&[0xFF]));
1467 {
1468 let db = Connection::open(&db_path)?;
1469 let sql = "BEGIN;
1470 CREATE TABLE foo(x INTEGER);
1471 INSERT INTO foo VALUES(42);
1472 END;";
1473 db.execute_batch(sql)?;
1474 }
1475
1476 let db = Connection::open(&db_path)?;
1477
1478 assert_eq!(42, db.one_column::<i64, _>("SELECT x FROM foo", [])?);
1479 Ok(())
1480 }
1481
1482 #[test]
1483 fn test_close_retry() -> Result<()> {
1484 let db = Connection::open_in_memory()?;
1485
1486 let raw_stmt = {
1490 use super::str_to_cstring;
1491 use std::ffi::c_int;
1492 use std::ptr;
1493
1494 let raw_db = db.db.borrow_mut().db;
1495 let sql = "SELECT 1";
1496 let mut raw_stmt: *mut ffi::sqlite3_stmt = ptr::null_mut();
1497 let cstring = str_to_cstring(sql)?;
1498 let rc = unsafe {
1499 ffi::sqlite3_prepare_v2(
1500 raw_db,
1501 cstring.as_ptr(),
1502 (sql.len() + 1) as c_int,
1503 &mut raw_stmt,
1504 ptr::null_mut(),
1505 )
1506 };
1507 assert_eq!(rc, ffi::SQLITE_OK);
1508 raw_stmt
1509 };
1510
1511 let (db, _) = db.close().unwrap_err();
1514 let (db, _) = db.close().unwrap_err();
1515 let (db, _) = db.close().unwrap_err();
1516
1517 assert_eq!(ffi::SQLITE_OK, unsafe { ffi::sqlite3_finalize(raw_stmt) });
1519
1520 db.close().unwrap();
1521 Ok(())
1522 }
1523
1524 #[test]
1525 fn test_open_with_flags() {
1526 for bad_flags in &[
1527 OpenFlags::empty(),
1528 OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_READ_WRITE,
1529 OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_CREATE,
1530 ] {
1531 Connection::open_in_memory_with_flags(*bad_flags).unwrap_err();
1532 }
1533 }
1534
1535 #[test]
1536 fn test_execute_batch() -> Result<()> {
1537 let db = Connection::open_in_memory()?;
1538 let sql = "BEGIN;
1539 CREATE TABLE foo(x INTEGER);
1540 INSERT INTO foo VALUES(1);
1541 INSERT INTO foo VALUES(2);
1542 INSERT INTO foo VALUES(3);
1543 INSERT INTO foo VALUES(4);
1544 END;";
1545 db.execute_batch(sql)?;
1546
1547 db.execute_batch("UPDATE foo SET x = 3 WHERE x < 3")?;
1548
1549 db.execute_batch("INVALID SQL").unwrap_err();
1550
1551 db.execute_batch("PRAGMA locking_mode = EXCLUSIVE")?;
1552 Ok(())
1553 }
1554
1555 #[test]
1556 fn test_execute() -> Result<()> {
1557 let db = Connection::open_in_memory()?;
1558 db.execute_batch("CREATE TABLE foo(x INTEGER)")?;
1559
1560 assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?1)", [1i32])?);
1561 assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?1)", [2i32])?);
1562
1563 assert_eq!(3, db.one_column::<i32, _>("SELECT SUM(x) FROM foo", [])?);
1564 Ok(())
1565 }
1566
1567 #[test]
1568 #[cfg(feature = "extra_check")]
1569 fn test_execute_select_with_no_row() {
1570 let db = checked_memory_handle();
1571 let err = db.execute("SELECT 1 WHERE 1 < ?1", [1i32]).unwrap_err();
1572 assert_eq!(
1573 err,
1574 Error::ExecuteReturnedResults,
1575 "Unexpected error: {err}"
1576 );
1577 }
1578
1579 #[test]
1580 fn test_execute_select_with_row() {
1581 let db = checked_memory_handle();
1582 let err = db.execute("SELECT 1", []).unwrap_err();
1583 assert_eq!(err, Error::ExecuteReturnedResults);
1584 }
1585
1586 #[test]
1587 fn test_execute_multiple() {
1588 let db = checked_memory_handle();
1589 let err = db
1590 .execute(
1591 "CREATE TABLE foo(x INTEGER); CREATE TABLE foo(x INTEGER)",
1592 [],
1593 )
1594 .unwrap_err();
1595 match err {
1596 Error::MultipleStatement => (),
1597 _ => panic!("Unexpected error: {err}"),
1598 }
1599 db.execute("CREATE TABLE t(c); -- bim", [])
1600 .expect("Tail comment should be ignored");
1601 }
1602
1603 #[test]
1604 fn test_prepare_column_names() -> Result<()> {
1605 let db = Connection::open_in_memory()?;
1606 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1607
1608 let stmt = db.prepare("SELECT * FROM foo")?;
1609 assert_eq!(stmt.column_count(), 1);
1610 assert_eq!(stmt.column_names(), vec!["x"]);
1611
1612 let stmt = db.prepare("SELECT x AS a, x AS b FROM foo")?;
1613 assert_eq!(stmt.column_count(), 2);
1614 assert_eq!(stmt.column_names(), vec!["a", "b"]);
1615 Ok(())
1616 }
1617
1618 #[test]
1619 fn test_prepare_execute() -> Result<()> {
1620 let db = Connection::open_in_memory()?;
1621 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1622
1623 let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?1)")?;
1624 assert_eq!(insert_stmt.execute([1i32])?, 1);
1625 assert_eq!(insert_stmt.execute([2i32])?, 1);
1626 assert_eq!(insert_stmt.execute([3i32])?, 1);
1627
1628 assert_eq!(insert_stmt.execute(["hello"])?, 1);
1629 assert_eq!(insert_stmt.execute(["goodbye"])?, 1);
1630 assert_eq!(insert_stmt.execute([types::Null])?, 1);
1631
1632 let mut update_stmt = db.prepare("UPDATE foo SET x=?1 WHERE x<?2")?;
1633 assert_eq!(update_stmt.execute([3i32, 3i32])?, 2);
1634 assert_eq!(update_stmt.execute([3i32, 3i32])?, 0);
1635 assert_eq!(update_stmt.execute([8i32, 8i32])?, 3);
1636 Ok(())
1637 }
1638
1639 #[test]
1640 fn test_prepare_query() -> Result<()> {
1641 let db = Connection::open_in_memory()?;
1642 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1643
1644 let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?1)")?;
1645 assert_eq!(insert_stmt.execute([1i32])?, 1);
1646 assert_eq!(insert_stmt.execute([2i32])?, 1);
1647 assert_eq!(insert_stmt.execute([3i32])?, 1);
1648
1649 let mut query = db.prepare("SELECT x FROM foo WHERE x < ?1 ORDER BY x DESC")?;
1650 {
1651 let mut rows = query.query([4i32])?;
1652 let mut v = Vec::<i32>::new();
1653
1654 while let Some(row) = rows.next()? {
1655 v.push(row.get(0)?);
1656 }
1657
1658 assert_eq!(v, [3i32, 2, 1]);
1659 }
1660
1661 {
1662 let mut rows = query.query([3i32])?;
1663 let mut v = Vec::<i32>::new();
1664
1665 while let Some(row) = rows.next()? {
1666 v.push(row.get(0)?);
1667 }
1668
1669 assert_eq!(v, [2i32, 1]);
1670 }
1671 Ok(())
1672 }
1673
1674 #[test]
1675 fn test_query_map() -> Result<()> {
1676 let db = Connection::open_in_memory()?;
1677 let sql = "BEGIN;
1678 CREATE TABLE foo(x INTEGER, y TEXT);
1679 INSERT INTO foo VALUES(4, \"hello\");
1680 INSERT INTO foo VALUES(3, \", \");
1681 INSERT INTO foo VALUES(2, \"world\");
1682 INSERT INTO foo VALUES(1, \"!\");
1683 END;";
1684 db.execute_batch(sql)?;
1685
1686 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1687 let results: Result<Vec<String>> = query.query([])?.map(|row| row.get(1)).collect();
1688
1689 assert_eq!(results?.concat(), "hello, world!");
1690 Ok(())
1691 }
1692
1693 #[test]
1694 fn test_query_row() -> Result<()> {
1695 let db = Connection::open_in_memory()?;
1696 let sql = "BEGIN;
1697 CREATE TABLE foo(x INTEGER);
1698 INSERT INTO foo VALUES(1);
1699 INSERT INTO foo VALUES(2);
1700 INSERT INTO foo VALUES(3);
1701 INSERT INTO foo VALUES(4);
1702 END;";
1703 db.execute_batch(sql)?;
1704
1705 assert_eq!(10, db.one_column::<i64, _>("SELECT SUM(x) FROM foo", [])?);
1706
1707 let result: Result<i64> = db.one_column("SELECT x FROM foo WHERE x > 5", []);
1708 match result.unwrap_err() {
1709 Error::QueryReturnedNoRows => (),
1710 err => panic!("Unexpected error {err}"),
1711 }
1712
1713 db.query_row("NOT A PROPER QUERY; test123", [], |_| Ok(()))
1714 .unwrap_err();
1715
1716 db.query_row("SELECT 1; SELECT 2;", [], |_| Ok(()))
1717 .unwrap_err();
1718
1719 Ok(())
1720 }
1721
1722 #[test]
1723 fn test_optional() -> Result<()> {
1724 let db = Connection::open_in_memory()?;
1725
1726 let result: Result<i64> = db.one_column("SELECT 1 WHERE 0 <> 0", []);
1727 let result = result.optional();
1728 match result? {
1729 None => (),
1730 _ => panic!("Unexpected result"),
1731 }
1732
1733 let result: Result<i64> = db.one_column("SELECT 1 WHERE 0 == 0", []);
1734 let result = result.optional();
1735 match result? {
1736 Some(1) => (),
1737 _ => panic!("Unexpected result"),
1738 }
1739
1740 let bad_query_result: Result<i64> = db.one_column("NOT A PROPER QUERY", []);
1741 let bad_query_result = bad_query_result.optional();
1742 bad_query_result.unwrap_err();
1743 Ok(())
1744 }
1745
1746 #[test]
1747 fn test_pragma_query_row() -> Result<()> {
1748 let db = Connection::open_in_memory()?;
1749 assert_eq!(
1750 "memory",
1751 db.one_column::<String, _>("PRAGMA journal_mode", [])?
1752 );
1753 let mode = db.one_column::<String, _>("PRAGMA journal_mode=off", [])?;
1754 if cfg!(feature = "bundled") {
1755 assert_eq!(mode, "off");
1756 } else {
1757 assert!(mode == "memory" || mode == "off", "Got mode {mode:?}");
1769 }
1770
1771 Ok(())
1772 }
1773
1774 #[test]
1775 fn test_prepare_failures() -> Result<()> {
1776 let db = Connection::open_in_memory()?;
1777 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1778
1779 let err = db.prepare("SELECT * FROM does_not_exist").unwrap_err();
1780 assert!(format!("{err}").contains("does_not_exist"));
1781 Ok(())
1782 }
1783
1784 #[test]
1785 fn test_last_insert_rowid() -> Result<()> {
1786 let db = Connection::open_in_memory()?;
1787 db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)")?;
1788 db.execute_batch("INSERT INTO foo DEFAULT VALUES")?;
1789
1790 assert_eq!(db.last_insert_rowid(), 1);
1791
1792 let mut stmt = db.prepare("INSERT INTO foo DEFAULT VALUES")?;
1793 for _ in 0i32..9 {
1794 stmt.execute([])?;
1795 }
1796 assert_eq!(db.last_insert_rowid(), 10);
1797 Ok(())
1798 }
1799
1800 #[test]
1801 fn test_total_changes() -> Result<()> {
1802 let db = Connection::open_in_memory()?;
1803 let sql = "CREATE TABLE foo(x INTEGER PRIMARY KEY, value TEXT default '' NOT NULL,
1804 desc TEXT default '');
1805 CREATE VIEW foo_bar AS SELECT x, desc FROM foo WHERE value = 'bar';
1806 CREATE TRIGGER INSERT_FOOBAR
1807 INSTEAD OF INSERT
1808 ON foo_bar
1809 BEGIN
1810 INSERT INTO foo VALUES(new.x, 'bar', new.desc);
1811 END;";
1812 db.execute_batch(sql)?;
1813 let total_changes_before = db.total_changes();
1814 let changes = db
1815 .prepare("INSERT INTO foo_bar VALUES(null, 'baz');")?
1816 .execute([])?;
1817 let total_changes_after = db.total_changes();
1818 assert_eq!(changes, 0);
1819 assert_eq!(total_changes_after - total_changes_before, 1);
1820 Ok(())
1821 }
1822
1823 #[test]
1824 fn test_is_autocommit() -> Result<()> {
1825 let db = Connection::open_in_memory()?;
1826 assert!(
1827 db.is_autocommit(),
1828 "autocommit expected to be active by default"
1829 );
1830 Ok(())
1831 }
1832
1833 #[test]
1834 fn test_is_busy() -> Result<()> {
1835 let db = Connection::open_in_memory()?;
1836 assert!(!db.is_busy());
1837 let mut stmt = db.prepare("PRAGMA schema_version")?;
1838 assert!(!db.is_busy());
1839 {
1840 let mut rows = stmt.query([])?;
1841 assert!(!db.is_busy());
1842 let row = rows.next()?;
1843 assert!(db.is_busy());
1844 assert!(row.is_some());
1845 }
1846 assert!(!db.is_busy());
1847 Ok(())
1848 }
1849
1850 #[test]
1851 fn test_statement_debugging() -> Result<()> {
1852 let db = Connection::open_in_memory()?;
1853 let query = "SELECT 12345";
1854 let stmt = db.prepare(query)?;
1855
1856 assert!(format!("{stmt:?}").contains(query));
1857 Ok(())
1858 }
1859
1860 #[test]
1861 fn test_notnull_constraint_error() -> Result<()> {
1862 let db = Connection::open_in_memory()?;
1863 db.execute_batch("CREATE TABLE foo(x NOT NULL)")?;
1864
1865 let result = db.execute("INSERT INTO foo (x) VALUES (NULL)", []);
1866
1867 match result.unwrap_err() {
1868 Error::SqliteFailure(err, _) => {
1869 assert_eq!(err.code, ErrorCode::ConstraintViolation);
1870 assert_eq!(err.extended_code, ffi::SQLITE_CONSTRAINT_NOTNULL);
1871 }
1872 err => panic!("Unexpected error {err}"),
1873 }
1874 Ok(())
1875 }
1876
1877 #[test]
1878 fn test_version_string() {
1879 let n = version_number();
1880 let major = n / 1_000_000;
1881 let minor = (n % 1_000_000) / 1_000;
1882 let patch = n % 1_000;
1883
1884 assert!(version().contains(&format!("{major}.{minor}.{patch}")));
1885 }
1886
1887 #[test]
1888 #[cfg(feature = "functions")]
1889 fn test_interrupt() -> Result<()> {
1890 let db = Connection::open_in_memory()?;
1891
1892 let interrupt_handle = db.get_interrupt_handle();
1893
1894 db.create_scalar_function(
1895 "interrupt",
1896 0,
1897 functions::FunctionFlags::default(),
1898 move |_| {
1899 interrupt_handle.interrupt();
1900 Ok(0)
1901 },
1902 )?;
1903
1904 let mut stmt =
1905 db.prepare("SELECT interrupt() FROM (SELECT 1 UNION SELECT 2 UNION SELECT 3)")?;
1906
1907 let result: Result<Vec<i32>> = stmt.query([])?.map(|r| r.get(0)).collect();
1908
1909 assert_eq!(
1910 result.unwrap_err().sqlite_error_code(),
1911 Some(ErrorCode::OperationInterrupted)
1912 );
1913 Ok(())
1914 }
1915
1916 #[test]
1917 fn test_interrupt_close() {
1918 let db = checked_memory_handle();
1919 let handle = db.get_interrupt_handle();
1920 handle.interrupt();
1921 db.close().unwrap();
1922 handle.interrupt();
1923
1924 let db_guard = handle.db_lock.lock().unwrap();
1926 assert!(db_guard.is_null());
1927 }
1931
1932 #[test]
1933 fn test_get_raw() -> Result<()> {
1934 let db = Connection::open_in_memory()?;
1935 db.execute_batch("CREATE TABLE foo(i, x);")?;
1936 let vals = ["foobar", "1234", "qwerty"];
1937 let mut insert_stmt = db.prepare("INSERT INTO foo(i, x) VALUES(?1, ?2)")?;
1938 for (i, v) in vals.iter().enumerate() {
1939 let i_to_insert = i as i64;
1940 assert_eq!(insert_stmt.execute(params![i_to_insert, v])?, 1);
1941 }
1942
1943 let mut query = db.prepare("SELECT i, x FROM foo")?;
1944 let mut rows = query.query([])?;
1945
1946 while let Some(row) = rows.next()? {
1947 let i = row.get_ref(0)?.as_i64()?;
1948 let expect = vals[i as usize];
1949 let x = row.get_ref("x")?.as_str()?;
1950 assert_eq!(x, expect);
1951 }
1952
1953 let mut query = db.prepare("SELECT x FROM foo")?;
1954 let rows = query.query_map([], |row| {
1955 let x = row.get_ref(0)?.as_str()?; Ok(x[..].to_owned())
1957 })?;
1958
1959 for (i, row) in rows.enumerate() {
1960 assert_eq!(row?, vals[i]);
1961 }
1962 Ok(())
1963 }
1964
1965 #[test]
1966 fn test_from_handle() -> Result<()> {
1967 let db = Connection::open_in_memory()?;
1968 let handle = unsafe { db.handle() };
1969 {
1970 let db = unsafe { Connection::from_handle(handle) }?;
1971 db.execute_batch("PRAGMA VACUUM")?;
1972 }
1973 db.close().unwrap();
1974 Ok(())
1975 }
1976
1977 #[test]
1978 fn test_from_handle_owned() -> Result<()> {
1979 let mut handle: *mut ffi::sqlite3 = std::ptr::null_mut();
1980 let r = unsafe { ffi::sqlite3_open(c":memory:".as_ptr(), &mut handle) };
1981 assert_eq!(r, ffi::SQLITE_OK);
1982 let db = unsafe { Connection::from_handle_owned(handle) }?;
1983 db.execute_batch("PRAGMA VACUUM")?;
1984 Ok(())
1985 }
1986
1987 mod query_and_then_tests {
1988 #[cfg(all(target_family = "wasm", target_os = "unknown"))]
1989 use wasm_bindgen_test::wasm_bindgen_test as test;
1990
1991 use super::*;
1992
1993 #[derive(Debug)]
1994 enum CustomError {
1995 SomeError,
1996 Sqlite(Error),
1997 }
1998
1999 impl fmt::Display for CustomError {
2000 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
2001 match *self {
2002 Self::SomeError => write!(f, "my custom error"),
2003 Self::Sqlite(ref se) => write!(f, "my custom error: {se}"),
2004 }
2005 }
2006 }
2007
2008 impl StdError for CustomError {
2009 fn description(&self) -> &str {
2010 "my custom error"
2011 }
2012
2013 fn cause(&self) -> Option<&dyn StdError> {
2014 match *self {
2015 Self::SomeError => None,
2016 Self::Sqlite(ref se) => Some(se),
2017 }
2018 }
2019 }
2020
2021 impl From<Error> for CustomError {
2022 fn from(se: Error) -> Self {
2023 Self::Sqlite(se)
2024 }
2025 }
2026
2027 type CustomResult<T> = Result<T, CustomError>;
2028
2029 #[test]
2030 fn test_query_and_then() -> Result<()> {
2031 let db = Connection::open_in_memory()?;
2032 let sql = "BEGIN;
2033 CREATE TABLE foo(x INTEGER, y TEXT);
2034 INSERT INTO foo VALUES(4, \"hello\");
2035 INSERT INTO foo VALUES(3, \", \");
2036 INSERT INTO foo VALUES(2, \"world\");
2037 INSERT INTO foo VALUES(1, \"!\");
2038 END;";
2039 db.execute_batch(sql)?;
2040
2041 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
2042 let results: Result<Vec<String>> =
2043 query.query_and_then([], |row| row.get(1))?.collect();
2044
2045 assert_eq!(results?.concat(), "hello, world!");
2046 Ok(())
2047 }
2048
2049 #[test]
2050 fn test_query_and_then_fails() -> Result<()> {
2051 let db = Connection::open_in_memory()?;
2052 let sql = "BEGIN;
2053 CREATE TABLE foo(x INTEGER, y TEXT);
2054 INSERT INTO foo VALUES(4, \"hello\");
2055 INSERT INTO foo VALUES(3, \", \");
2056 INSERT INTO foo VALUES(2, \"world\");
2057 INSERT INTO foo VALUES(1, \"!\");
2058 END;";
2059 db.execute_batch(sql)?;
2060
2061 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
2062 let bad_type: Result<Vec<f64>> = query.query_and_then([], |row| row.get(1))?.collect();
2063
2064 match bad_type.unwrap_err() {
2065 Error::InvalidColumnType(..) => (),
2066 err => panic!("Unexpected error {err}"),
2067 }
2068
2069 let bad_idx: Result<Vec<String>> =
2070 query.query_and_then([], |row| row.get(3))?.collect();
2071
2072 match bad_idx.unwrap_err() {
2073 Error::InvalidColumnIndex(_) => (),
2074 err => panic!("Unexpected error {err}"),
2075 }
2076 Ok(())
2077 }
2078
2079 #[test]
2080 fn test_query_and_then_custom_error() -> CustomResult<()> {
2081 let db = Connection::open_in_memory()?;
2082 let sql = "BEGIN;
2083 CREATE TABLE foo(x INTEGER, y TEXT);
2084 INSERT INTO foo VALUES(4, \"hello\");
2085 INSERT INTO foo VALUES(3, \", \");
2086 INSERT INTO foo VALUES(2, \"world\");
2087 INSERT INTO foo VALUES(1, \"!\");
2088 END;";
2089 db.execute_batch(sql)?;
2090
2091 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
2092 let results: CustomResult<Vec<String>> = query
2093 .query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite))?
2094 .collect();
2095
2096 assert_eq!(results?.concat(), "hello, world!");
2097 Ok(())
2098 }
2099
2100 #[test]
2101 fn test_query_and_then_custom_error_fails() -> Result<()> {
2102 let db = Connection::open_in_memory()?;
2103 let sql = "BEGIN;
2104 CREATE TABLE foo(x INTEGER, y TEXT);
2105 INSERT INTO foo VALUES(4, \"hello\");
2106 INSERT INTO foo VALUES(3, \", \");
2107 INSERT INTO foo VALUES(2, \"world\");
2108 INSERT INTO foo VALUES(1, \"!\");
2109 END;";
2110 db.execute_batch(sql)?;
2111
2112 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
2113 let bad_type: CustomResult<Vec<f64>> = query
2114 .query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite))?
2115 .collect();
2116
2117 match bad_type.unwrap_err() {
2118 CustomError::Sqlite(Error::InvalidColumnType(..)) => (),
2119 err => panic!("Unexpected error {err}"),
2120 }
2121
2122 let bad_idx: CustomResult<Vec<String>> = query
2123 .query_and_then([], |row| row.get(3).map_err(CustomError::Sqlite))?
2124 .collect();
2125
2126 match bad_idx.unwrap_err() {
2127 CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
2128 err => panic!("Unexpected error {err}"),
2129 }
2130
2131 let non_sqlite_err: CustomResult<Vec<String>> = query
2132 .query_and_then([], |_| Err(CustomError::SomeError))?
2133 .collect();
2134
2135 match non_sqlite_err.unwrap_err() {
2136 CustomError::SomeError => (),
2137 err => panic!("Unexpected error {err}"),
2138 }
2139 Ok(())
2140 }
2141
2142 #[test]
2143 fn test_query_row_and_then_custom_error() -> CustomResult<()> {
2144 let db = Connection::open_in_memory()?;
2145 let sql = "BEGIN;
2146 CREATE TABLE foo(x INTEGER, y TEXT);
2147 INSERT INTO foo VALUES(4, \"hello\");
2148 END;";
2149 db.execute_batch(sql)?;
2150
2151 let query = "SELECT x, y FROM foo ORDER BY x DESC";
2152 let results: CustomResult<String> =
2153 db.query_row_and_then(query, [], |row| row.get(1).map_err(CustomError::Sqlite));
2154
2155 assert_eq!(results?, "hello");
2156 Ok(())
2157 }
2158
2159 #[test]
2160 fn test_query_row_and_then_custom_error_fails() -> Result<()> {
2161 let db = Connection::open_in_memory()?;
2162 let sql = "BEGIN;
2163 CREATE TABLE foo(x INTEGER, y TEXT);
2164 INSERT INTO foo VALUES(4, \"hello\");
2165 END;";
2166 db.execute_batch(sql)?;
2167
2168 let query = "SELECT x, y FROM foo ORDER BY x DESC";
2169 let bad_type: CustomResult<f64> =
2170 db.query_row_and_then(query, [], |row| row.get(1).map_err(CustomError::Sqlite));
2171
2172 match bad_type.unwrap_err() {
2173 CustomError::Sqlite(Error::InvalidColumnType(..)) => (),
2174 err => panic!("Unexpected error {err}"),
2175 }
2176
2177 let bad_idx: CustomResult<String> =
2178 db.query_row_and_then(query, [], |row| row.get(3).map_err(CustomError::Sqlite));
2179
2180 match bad_idx.unwrap_err() {
2181 CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
2182 err => panic!("Unexpected error {err}"),
2183 }
2184
2185 let non_sqlite_err: CustomResult<String> =
2186 db.query_row_and_then(query, [], |_| Err(CustomError::SomeError));
2187
2188 match non_sqlite_err.unwrap_err() {
2189 CustomError::SomeError => (),
2190 err => panic!("Unexpected error {err}"),
2191 }
2192 Ok(())
2193 }
2194 }
2195
2196 #[test]
2197 fn test_dynamic() -> Result<()> {
2198 let db = Connection::open_in_memory()?;
2199 let sql = "BEGIN;
2200 CREATE TABLE foo(x INTEGER, y TEXT);
2201 INSERT INTO foo VALUES(4, \"hello\");
2202 END;";
2203 db.execute_batch(sql)?;
2204
2205 db.query_row("SELECT * FROM foo", [], |r| {
2206 assert_eq!(2, r.as_ref().column_count());
2207 Ok(())
2208 })
2209 }
2210 #[test]
2211 fn test_dyn_box() -> Result<()> {
2212 let db = Connection::open_in_memory()?;
2213 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
2214 let b: Box<dyn ToSql> = Box::new(5);
2215 db.execute("INSERT INTO foo VALUES(?1)", [b])?;
2216 db.query_row("SELECT x FROM foo", [], |r| {
2217 assert_eq!(5, r.get_unwrap::<_, i32>(0));
2218 Ok(())
2219 })
2220 }
2221
2222 #[test]
2223 fn test_params() -> Result<()> {
2224 let db = Connection::open_in_memory()?;
2225 db.query_row(
2226 "SELECT
2227 ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10,
2228 ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19, ?20,
2229 ?21, ?22, ?23, ?24, ?25, ?26, ?27, ?28, ?29, ?30,
2230 ?31, ?32, ?33, ?34;",
2231 params![
2232 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,
2233 1, 1, 1, 1, 1, 1,
2234 ],
2235 |r| {
2236 assert_eq!(1, r.get_unwrap::<_, i32>(0));
2237 Ok(())
2238 },
2239 )
2240 }
2241
2242 #[test]
2243 fn test_alter_table() -> Result<()> {
2244 let db = Connection::open_in_memory()?;
2245 db.execute_batch("CREATE TABLE x(t);")?;
2246 db.execute("ALTER TABLE x RENAME TO y;", [])?;
2248 Ok(())
2249 }
2250
2251 #[test]
2252 fn test_batch() -> Result<()> {
2253 let db = Connection::open_in_memory()?;
2254 let sql = r"
2255 CREATE TABLE tbl1 (col);
2256 CREATE TABLE tbl2 (col);
2257 ";
2258 let mut batch = Batch::new(&db, sql);
2259 while let Some(mut stmt) = batch.next()? {
2260 stmt.execute([])?;
2261 }
2262 Ok(())
2263 }
2264
2265 #[test]
2266 fn test_invalid_batch() -> Result<()> {
2267 let db = Connection::open_in_memory()?;
2268 let sql = r"
2269 PRAGMA test1;
2270 PRAGMA test2=?;
2271 PRAGMA test3;
2272 ";
2273 let mut batch = Batch::new(&db, sql);
2274 assert!(batch.next().is_ok());
2275 assert!(batch.next().is_err());
2276 assert!(batch.next().is_err());
2277 assert!(Batch::new(&db, sql).count().is_err());
2278 Ok(())
2279 }
2280
2281 #[test]
2282 #[cfg(feature = "modern_sqlite")]
2283 fn test_returning() -> Result<()> {
2284 let db = Connection::open_in_memory()?;
2285 db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)")?;
2286 let row_id =
2287 db.one_column::<i64, _>("INSERT INTO foo DEFAULT VALUES RETURNING ROWID", [])?;
2288 assert_eq!(row_id, 1);
2289 Ok(())
2290 }
2291
2292 #[test]
2293 fn test_cache_flush() -> Result<()> {
2294 let db = Connection::open_in_memory()?;
2295 db.cache_flush()
2296 }
2297
2298 #[test]
2299 fn db_readonly() -> Result<()> {
2300 let db = Connection::open_in_memory()?;
2301 assert!(!db.is_readonly(MAIN_DB)?);
2302 Ok(())
2303 }
2304
2305 #[test]
2306 #[cfg(feature = "rusqlite-macros")]
2307 fn prepare_and_bind() -> Result<()> {
2308 let db = Connection::open_in_memory()?;
2309 let name = "Lisa";
2310 let age = 8;
2311 let mut stmt = prepare_and_bind!(db, "SELECT $name, $age;");
2312 let (v1, v2) = stmt
2313 .raw_query()
2314 .next()
2315 .and_then(|o| o.ok_or(Error::QueryReturnedNoRows))
2316 .and_then(|r| Ok((r.get::<_, String>(0)?, r.get::<_, i64>(1)?)))?;
2317 assert_eq!((v1.as_str(), v2), (name, age));
2318 Ok(())
2319 }
2320
2321 #[test]
2322 #[cfg(feature = "modern_sqlite")]
2323 fn test_db_name() -> Result<()> {
2324 let db = Connection::open_in_memory()?;
2325 assert_eq!(db.db_name(0)?, "main");
2326 assert_eq!(db.db_name(1)?, "temp");
2327 assert_eq!(db.db_name(2), Err(Error::InvalidDatabaseIndex(2)));
2328 db.execute_batch("ATTACH DATABASE ':memory:' AS xyz;")?;
2329 assert_eq!(db.db_name(2)?, "xyz");
2330 Ok(())
2331 }
2332
2333 #[test]
2334 #[cfg(feature = "modern_sqlite")]
2335 fn test_is_interrupted() -> Result<()> {
2336 let db = Connection::open_in_memory()?;
2337 assert!(!db.is_interrupted());
2338 db.get_interrupt_handle().interrupt();
2339 assert!(db.is_interrupted());
2340 Ok(())
2341 }
2342
2343 #[test]
2344 fn release_memory() -> Result<()> {
2345 let db = Connection::open_in_memory()?;
2346 db.release_memory()
2347 }
2348
2349 #[test]
2350 #[cfg(feature = "modern_sqlite")] fn set_errmsg() -> Result<()> {
2352 let db = Connection::open_in_memory()?;
2353 let code: i32 = ffi::SQLITE_MISUSE;
2354 let msg = c"Oops";
2355 db.set_errmsg(code, Some(msg))?;
2356 let ptr = unsafe { db.handle() };
2357 assert_eq!(unsafe { ffi::sqlite3_errcode(ptr) }, code);
2358 assert_eq!(
2359 unsafe { std::ffi::CStr::from_ptr(ffi::sqlite3_errmsg(ptr)) },
2360 msg
2361 );
2362 Ok(())
2363 }
2364}