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(target_family = "wasm", target_os = "unknown")))]
61pub use libsqlite3_sys as ffi;
62#[cfg(all(target_family = "wasm", target_os = "unknown"))]
63pub use sqlite_wasm_rs as ffi;
64
65use std::cell::RefCell;
66use std::default::Default;
67use std::ffi::{c_char, c_int, c_uint, CStr, CString};
68use std::fmt;
69
70use std::path::Path;
71use std::result;
72use std::str;
73use std::sync::{Arc, Mutex};
74
75#[cfg(feature = "cache")]
76use crate::cache::StatementCache;
77use crate::inner_connection::InnerConnection;
78use crate::raw_statement::RawStatement;
79use crate::types::ValueRef;
80
81pub use crate::bind::BindIndex;
82#[cfg(feature = "cache")]
83pub use crate::cache::CachedStatement;
84#[cfg(feature = "column_decltype")]
85pub use crate::column::Column;
86#[cfg(feature = "column_metadata")]
87pub use crate::column::ColumnMetadata;
88pub use crate::error::{to_sqlite_error, Error};
89pub use crate::ffi::ErrorCode;
90#[cfg(feature = "load_extension")]
91pub use crate::load_extension_guard::LoadExtensionGuard;
92pub use crate::params::{params_from_iter, Params, ParamsFromIter};
93pub use crate::row::{AndThenRows, Map, MappedRows, Row, RowIndex, Rows};
94pub use crate::statement::{Statement, StatementStatus};
95#[cfg(feature = "modern_sqlite")]
96pub use crate::transaction::TransactionState;
97pub use crate::transaction::{DropBehavior, Savepoint, Transaction, TransactionBehavior};
98pub use crate::types::ToSql;
99pub use crate::util::Name;
100pub use crate::version::*;
101#[cfg(feature = "rusqlite-macros")]
102#[doc(hidden)]
103pub use rusqlite_macros::__bind;
104
105#[macro_use]
106mod error;
107
108#[cfg(not(feature = "loadable_extension"))]
109pub mod auto_extension;
110#[cfg(feature = "backup")]
111pub mod backup;
112mod bind;
113#[cfg(feature = "blob")]
114pub mod blob;
115mod busy;
116#[cfg(feature = "cache")]
117mod cache;
118#[cfg(feature = "collation")]
119mod collation;
120mod column;
121pub mod config;
122#[cfg(any(feature = "functions", feature = "vtab"))]
123mod context;
124#[cfg(feature = "functions")]
125pub mod functions;
126#[cfg(feature = "hooks")]
127pub mod hooks;
128mod inner_connection;
129#[cfg(feature = "limits")]
130pub mod limits;
131#[cfg(feature = "load_extension")]
132mod load_extension_guard;
133mod params;
134mod pragma;
135mod raw_statement;
136mod row;
137#[cfg(feature = "serialize")]
138pub mod serialize;
139#[cfg(feature = "session")]
140pub mod session;
141mod statement;
142#[cfg(feature = "trace")]
143pub mod trace;
144mod transaction;
145pub mod types;
146#[cfg(feature = "unlock_notify")]
147mod unlock_notify;
148mod version;
149#[cfg(feature = "vtab")]
150pub mod vtab;
151
152pub(crate) mod util;
153
154#[cfg(all(feature = "loadable_extension", feature = "load_extension"))]
156compile_error!("feature \"loadable_extension\" and feature \"load_extension\" cannot be enabled at the same time");
157
158#[cfg(feature = "cache")]
160const STATEMENT_CACHE_DEFAULT_CAPACITY: usize = 16;
161
162#[macro_export]
185macro_rules! params {
186 () => {
187 &[] as &[&dyn $crate::ToSql]
188 };
189 ($($param:expr),+ $(,)?) => {
190 &[$(&$param as &dyn $crate::ToSql),+] as &[&dyn $crate::ToSql]
191 };
192}
193
194#[macro_export]
222macro_rules! named_params {
223 () => {
224 &[] as &[(&str, &dyn $crate::ToSql)]
225 };
226 ($($param_name:literal: $param_val:expr),+ $(,)?) => {
229 &[$(($param_name, &$param_val as &dyn $crate::ToSql)),+] as &[(&str, &dyn $crate::ToSql)]
230 };
231}
232
233#[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#[macro_export]
268macro_rules! prepare_cached_and_bind {
269 ($conn:expr, $sql:literal) => {{
270 let mut stmt = $conn.prepare_cached($sql)?;
271 $crate::__bind!(stmt $sql);
272 stmt
273 }};
274}
275
276pub type Result<T, E = Error> = result::Result<T, E>;
278
279pub trait OptionalExtension<T> {
281 fn optional(self) -> Result<Option<T>>;
287}
288
289impl<T> OptionalExtension<T> for Result<T> {
290 fn optional(self) -> Result<Option<T>> {
291 match self {
292 Ok(value) => Ok(Some(value)),
293 Err(Error::QueryReturnedNoRows) => Ok(None),
294 Err(e) => Err(e),
295 }
296 }
297}
298
299unsafe fn errmsg_to_string(errmsg: *const c_char) -> String {
300 CStr::from_ptr(errmsg).to_string_lossy().into_owned()
301}
302
303#[cfg(any(feature = "functions", feature = "vtab", test))]
304fn str_to_cstring(s: &str) -> Result<util::SmallCString> {
305 Ok(util::SmallCString::new(s)?)
306}
307
308fn str_for_sqlite(
314 s: &[u8],
315) -> (
316 *const c_char,
317 ffi::sqlite3_uint64,
318 ffi::sqlite3_destructor_type,
319) {
320 let len = s.len();
321 let (ptr, dtor_info) = if len != 0 {
322 (s.as_ptr().cast::<c_char>(), ffi::SQLITE_TRANSIENT())
323 } else {
324 ("".as_ptr().cast::<c_char>(), ffi::SQLITE_STATIC())
326 };
327 (ptr, len as ffi::sqlite3_uint64, dtor_info)
328}
329
330#[cfg(unix)]
331fn path_to_cstring(p: &Path) -> Result<CString> {
332 use std::os::unix::ffi::OsStrExt;
333 Ok(CString::new(p.as_os_str().as_bytes())?)
334}
335
336#[cfg(not(unix))]
337fn path_to_cstring(p: &Path) -> Result<CString> {
338 let s = p.to_str().ok_or_else(|| Error::InvalidPath(p.to_owned()))?;
339 Ok(CString::new(s)?)
340}
341
342pub const MAIN_DB: &CStr = c"main";
344pub const TEMP_DB: &CStr = c"temp";
346
347pub struct Connection {
349 db: RefCell<InnerConnection>,
350 #[cfg(feature = "cache")]
351 cache: StatementCache,
352 transaction_behavior: TransactionBehavior,
353}
354
355unsafe impl Send for Connection {}
356
357impl Drop for Connection {
358 #[inline]
359 fn drop(&mut self) {
360 #[cfg(feature = "cache")]
361 self.flush_prepared_statement_cache();
362 }
363}
364
365impl Connection {
366 #[inline]
428 pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
429 let flags = OpenFlags::default();
430 Self::open_with_flags(path, flags)
431 }
432
433 #[inline]
439 pub fn open_in_memory() -> Result<Self> {
440 let flags = OpenFlags::default();
441 Self::open_in_memory_with_flags(flags)
442 }
443
444 #[inline]
454 pub fn open_with_flags<P: AsRef<Path>>(path: P, flags: OpenFlags) -> Result<Self> {
455 let c_path = path_to_cstring(path.as_ref())?;
456 InnerConnection::open_with_flags(&c_path, flags, None).map(|db| Self {
457 db: RefCell::new(db),
458 #[cfg(feature = "cache")]
459 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
460 transaction_behavior: TransactionBehavior::Deferred,
461 })
462 }
463
464 #[inline]
475 pub fn open_with_flags_and_vfs<P: AsRef<Path>, V: Name>(
476 path: P,
477 flags: OpenFlags,
478 vfs: V,
479 ) -> Result<Self> {
480 let c_path = path_to_cstring(path.as_ref())?;
481 let c_vfs = vfs.as_cstr()?;
482 InnerConnection::open_with_flags(&c_path, flags, Some(&c_vfs)).map(|db| Self {
483 db: RefCell::new(db),
484 #[cfg(feature = "cache")]
485 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
486 transaction_behavior: TransactionBehavior::Deferred,
487 })
488 }
489
490 #[inline]
499 pub fn open_in_memory_with_flags(flags: OpenFlags) -> Result<Self> {
500 Self::open_with_flags(":memory:", flags)
501 }
502
503 #[inline]
514 pub fn open_in_memory_with_flags_and_vfs<V: Name>(flags: OpenFlags, vfs: V) -> Result<Self> {
515 Self::open_with_flags_and_vfs(":memory:", flags, vfs)
516 }
517
518 pub fn execute_batch(&self, sql: &str) -> Result<()> {
540 let mut sql = sql;
541 while !sql.is_empty() {
542 let (stmt, tail) = self
543 .db
544 .borrow_mut()
545 .prepare(self, sql, PrepFlags::default())?;
546 if !stmt.stmt.is_null() && stmt.step()? {
547 if false {
549 return Err(Error::ExecuteReturnedResults);
550 }
551 }
552 if tail == 0 || tail >= sql.len() {
553 break;
554 }
555 sql = &sql[tail..];
556 }
557 Ok(())
558 }
559
560 #[inline]
611 pub fn execute<P: Params>(&self, sql: &str, params: P) -> Result<usize> {
612 self.prepare(sql).and_then(|mut stmt| stmt.execute(params))
613 }
614
615 #[inline]
623 pub fn path(&self) -> Option<&str> {
624 unsafe { inner_connection::db_filename(std::marker::PhantomData, self.handle(), MAIN_DB) }
625 }
626
627 #[inline]
632 pub fn release_memory(&self) -> Result<()> {
633 self.db.borrow_mut().release_memory()
634 }
635
636 #[inline]
641 pub fn last_insert_rowid(&self) -> i64 {
642 self.db.borrow_mut().last_insert_rowid()
643 }
644
645 #[inline]
673 pub fn query_row<T, P, F>(&self, sql: &str, params: P, f: F) -> Result<T>
674 where
675 P: Params,
676 F: FnOnce(&Row<'_>) -> Result<T>,
677 {
678 let mut stmt = self.prepare(sql)?;
679 stmt.query_row(params, f)
680 }
681
682 pub fn query_one<T, P, F>(&self, sql: &str, params: P, f: F) -> Result<T>
697 where
698 P: Params,
699 F: FnOnce(&Row<'_>) -> Result<T>,
700 {
701 let mut stmt = self.prepare(sql)?;
702 stmt.query_one(params, f)
703 }
704
705 #[cfg(test)]
707 pub(crate) fn one_column<T, P>(&self, sql: &str, params: P) -> Result<T>
708 where
709 T: types::FromSql,
710 P: Params,
711 {
712 self.query_one(sql, params, |r| r.get(0))
713 }
714
715 #[inline]
741 pub fn query_row_and_then<T, E, P, F>(&self, sql: &str, params: P, f: F) -> Result<T, E>
742 where
743 P: Params,
744 F: FnOnce(&Row<'_>) -> Result<T, E>,
745 E: From<Error>,
746 {
747 let mut stmt = self.prepare(sql)?;
748 let mut rows = stmt.query(params)?;
749
750 rows.get_expected_row().map_err(E::from).and_then(f)
751 }
752
753 #[inline]
772 pub fn prepare(&self, sql: &str) -> Result<Statement<'_>> {
773 self.prepare_with_flags(sql, PrepFlags::default())
774 }
775
776 #[inline]
783 pub fn prepare_with_flags(&self, sql: &str, flags: PrepFlags) -> Result<Statement<'_>> {
784 let (stmt, tail) = self.db.borrow_mut().prepare(self, sql, flags)?;
785 if tail != 0 && !self.prepare(&sql[tail..])?.stmt.is_null() {
786 Err(Error::MultipleStatement)
787 } else {
788 Ok(stmt)
789 }
790 }
791
792 #[expect(clippy::result_large_err)]
802 #[inline]
803 pub fn close(self) -> Result<(), (Self, Error)> {
804 #[cfg(feature = "cache")]
805 self.flush_prepared_statement_cache();
806 let r = self.db.borrow_mut().close();
807 r.map_err(move |err| (self, err))
808 }
809
810 #[cfg(feature = "load_extension")]
863 #[inline]
864 pub unsafe fn load_extension_enable(&self) -> Result<()> {
865 self.db.borrow_mut().enable_load_extension(1)
866 }
867
868 #[cfg(feature = "load_extension")]
876 #[inline]
877 pub fn load_extension_disable(&self) -> Result<()> {
878 unsafe { self.db.borrow_mut().enable_load_extension(0) }
880 }
881
882 #[cfg(feature = "load_extension")]
918 #[inline]
919 pub unsafe fn load_extension<P: AsRef<Path>, N: Name>(
920 &self,
921 dylib_path: P,
922 entry_point: Option<N>,
923 ) -> Result<()> {
924 self.db
925 .borrow_mut()
926 .load_extension(dylib_path.as_ref(), entry_point)
927 }
928
929 #[inline]
943 pub unsafe fn handle(&self) -> *mut ffi::sqlite3 {
944 self.db.borrow().db()
945 }
946
947 #[inline]
956 pub unsafe fn from_handle(db: *mut ffi::sqlite3) -> Result<Self> {
957 let db = InnerConnection::new(db, false);
958 Ok(Self {
959 db: RefCell::new(db),
960 #[cfg(feature = "cache")]
961 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
962 transaction_behavior: TransactionBehavior::Deferred,
963 })
964 }
965
966 #[cfg(feature = "loadable_extension")]
972 pub unsafe fn extension_init2(
973 db: *mut ffi::sqlite3,
974 pz_err_msg: *mut *mut c_char,
975 p_api: *mut ffi::sqlite3_api_routines,
976 init: fn(Self) -> Result<bool>,
977 ) -> c_int {
978 if p_api.is_null() {
979 return ffi::SQLITE_ERROR;
980 }
981 match ffi::rusqlite_extension_init2(p_api)
982 .map_err(Error::from)
983 .and(Self::from_handle(db))
984 .and_then(init)
985 {
986 Err(err) => to_sqlite_error(&err, pz_err_msg),
987 Ok(true) => ffi::SQLITE_OK_LOAD_PERMANENTLY,
988 _ => ffi::SQLITE_OK,
989 }
990 }
991
992 #[inline]
1005 pub unsafe fn from_handle_owned(db: *mut ffi::sqlite3) -> Result<Self> {
1006 let db = InnerConnection::new(db, true);
1007 Ok(Self {
1008 db: RefCell::new(db),
1009 #[cfg(feature = "cache")]
1010 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
1011 transaction_behavior: TransactionBehavior::Deferred,
1012 })
1013 }
1014
1015 #[inline]
1018 pub fn get_interrupt_handle(&self) -> InterruptHandle {
1019 self.db.borrow().get_interrupt_handle()
1020 }
1021
1022 #[inline]
1023 fn decode_result(&self, code: c_int) -> Result<()> {
1024 self.db.borrow().decode_result(code)
1025 }
1026
1027 #[inline]
1033 pub fn changes(&self) -> u64 {
1034 self.db.borrow().changes()
1035 }
1036
1037 #[inline]
1043 pub fn total_changes(&self) -> u64 {
1044 self.db.borrow().total_changes()
1045 }
1046
1047 #[inline]
1050 pub fn is_autocommit(&self) -> bool {
1051 self.db.borrow().is_autocommit()
1052 }
1053
1054 #[inline]
1056 pub fn is_busy(&self) -> bool {
1057 self.db.borrow().is_busy()
1058 }
1059
1060 pub fn cache_flush(&self) -> Result<()> {
1062 self.db.borrow_mut().cache_flush()
1063 }
1064
1065 pub fn is_readonly<N: Name>(&self, db_name: N) -> Result<bool> {
1067 self.db.borrow().db_readonly(db_name)
1068 }
1069
1070 #[cfg(feature = "modern_sqlite")] pub fn db_name(&self, index: usize) -> Result<String> {
1077 unsafe {
1078 let db = self.handle();
1079 let name = ffi::sqlite3_db_name(db, index as c_int);
1080 if name.is_null() {
1081 Err(Error::InvalidDatabaseIndex(index))
1082 } else {
1083 Ok(CStr::from_ptr(name).to_str()?.to_owned())
1084 }
1085 }
1086 }
1087
1088 #[cfg(feature = "modern_sqlite")] pub fn is_interrupted(&self) -> bool {
1091 self.db.borrow().is_interrupted()
1092 }
1093}
1094
1095impl fmt::Debug for Connection {
1096 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1097 f.debug_struct("Connection")
1098 .field("path", &self.path())
1099 .finish()
1100 }
1101}
1102
1103#[derive(Debug)]
1128pub struct Batch<'conn, 'sql> {
1129 conn: &'conn Connection,
1130 sql: &'sql str,
1131 tail: usize,
1132}
1133
1134impl<'conn, 'sql> Batch<'conn, 'sql> {
1135 pub fn new(conn: &'conn Connection, sql: &'sql str) -> Self {
1137 Batch { conn, sql, tail: 0 }
1138 }
1139}
1140impl<'conn> fallible_iterator::FallibleIterator for Batch<'conn, '_> {
1141 type Item = Statement<'conn>;
1142 type Error = Error;
1143
1144 fn next(&mut self) -> Result<Option<Statement<'conn>>> {
1148 while self.tail < self.sql.len() {
1149 let sql = &self.sql[self.tail..];
1150 let (next, tail) =
1151 self.conn
1152 .db
1153 .borrow_mut()
1154 .prepare(self.conn, sql, PrepFlags::default())?;
1155 if tail == 0 {
1156 self.tail = self.sql.len();
1157 } else {
1158 self.tail += tail;
1159 }
1160 if next.stmt.is_null() {
1161 continue;
1162 }
1163 return Ok(Some(next));
1164 }
1165 Ok(None)
1166 }
1167}
1168
1169bitflags::bitflags! {
1170 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1177 #[repr(C)]
1178 pub struct OpenFlags: c_int {
1179 const SQLITE_OPEN_READ_ONLY = ffi::SQLITE_OPEN_READONLY;
1182 const SQLITE_OPEN_READ_WRITE = ffi::SQLITE_OPEN_READWRITE;
1186 const SQLITE_OPEN_CREATE = ffi::SQLITE_OPEN_CREATE;
1188 const SQLITE_OPEN_URI = ffi::SQLITE_OPEN_URI;
1190 const SQLITE_OPEN_MEMORY = ffi::SQLITE_OPEN_MEMORY;
1192 const SQLITE_OPEN_NO_MUTEX = ffi::SQLITE_OPEN_NOMUTEX;
1201 const SQLITE_OPEN_FULL_MUTEX = ffi::SQLITE_OPEN_FULLMUTEX;
1225 const SQLITE_OPEN_SHARED_CACHE = 0x0002_0000;
1232 const SQLITE_OPEN_PRIVATE_CACHE = 0x0004_0000;
1234 const SQLITE_OPEN_NOFOLLOW = 0x0100_0000;
1236 const SQLITE_OPEN_EXRESCODE = 0x0200_0000;
1238 }
1239}
1240
1241impl Default for OpenFlags {
1242 #[inline]
1243 fn default() -> Self {
1244 Self::SQLITE_OPEN_READ_WRITE
1247 | Self::SQLITE_OPEN_CREATE
1248 | Self::SQLITE_OPEN_NO_MUTEX
1249 | Self::SQLITE_OPEN_URI
1250 }
1251}
1252
1253bitflags::bitflags! {
1254 #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
1257 #[repr(C)]
1258 pub struct PrepFlags: c_uint {
1259 const SQLITE_PREPARE_PERSISTENT = 0x01;
1261 const SQLITE_PREPARE_NO_VTAB = 0x04;
1263 const SQLITE_PREPARE_DONT_LOG = 0x10;
1265 }
1266}
1267
1268pub struct InterruptHandle {
1270 db_lock: Arc<Mutex<*mut ffi::sqlite3>>,
1271}
1272
1273unsafe impl Send for InterruptHandle {}
1274unsafe impl Sync for InterruptHandle {}
1275
1276impl InterruptHandle {
1277 pub fn interrupt(&self) {
1280 let db_handle = self.db_lock.lock().unwrap();
1281 if !db_handle.is_null() {
1282 unsafe { ffi::sqlite3_interrupt(*db_handle) }
1283 }
1284 }
1285}
1286
1287#[cfg(doctest)]
1288doc_comment::doctest!("../README.md");
1289
1290#[cfg(test)]
1291mod test {
1292 #[cfg(all(target_family = "wasm", target_os = "unknown"))]
1293 use wasm_bindgen_test::wasm_bindgen_test as test;
1294
1295 use super::*;
1296 use fallible_iterator::FallibleIterator;
1297 use std::error::Error as StdError;
1298 use std::fmt;
1299
1300 #[allow(dead_code)]
1304 #[expect(unconditional_recursion, clippy::extra_unused_type_parameters)]
1305 fn ensure_send<T: Send>() {
1306 ensure_send::<Connection>();
1307 ensure_send::<InterruptHandle>();
1308 }
1309
1310 #[allow(dead_code)]
1311 #[expect(unconditional_recursion, clippy::extra_unused_type_parameters)]
1312 fn ensure_sync<T: Sync>() {
1313 ensure_sync::<InterruptHandle>();
1314 }
1315
1316 fn checked_memory_handle() -> Connection {
1317 Connection::open_in_memory().unwrap()
1318 }
1319
1320 #[cfg_attr(
1321 all(target_family = "wasm", target_os = "unknown"),
1322 ignore = "no filesystem on this platform"
1323 )]
1324 #[test]
1325 fn test_concurrent_transactions_busy_commit() -> Result<()> {
1326 use std::time::Duration;
1327 let tmp = tempfile::tempdir().unwrap();
1328 let path = tmp.path().join("transactions.db3");
1329
1330 Connection::open(&path)?.execute_batch(
1331 "
1332 BEGIN; CREATE TABLE foo(x INTEGER);
1333 INSERT INTO foo VALUES(42); END;",
1334 )?;
1335
1336 let mut db1 = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_WRITE)?;
1337 let mut db2 = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_ONLY)?;
1338
1339 db1.busy_timeout(Duration::from_millis(0))?;
1340 db2.busy_timeout(Duration::from_millis(0))?;
1341
1342 {
1343 let tx1 = db1.transaction()?;
1344 let tx2 = db2.transaction()?;
1345
1346 tx1.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))?;
1348 tx2.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))?;
1349
1350 tx1.execute("INSERT INTO foo VALUES(?1)", [1])?;
1351 let _ = tx2.execute("INSERT INTO foo VALUES(?1)", [2]);
1352
1353 let _ = tx1.commit();
1354 let _ = tx2.commit();
1355 }
1356
1357 let _ = db1
1358 .transaction()
1359 .expect("commit should have closed transaction");
1360 let _ = db2
1361 .transaction()
1362 .expect("commit should have closed transaction");
1363 Ok(())
1364 }
1365
1366 #[cfg_attr(
1367 all(target_family = "wasm", target_os = "unknown"),
1368 ignore = "no filesystem on this platform"
1369 )]
1370 #[test]
1371 fn test_persistence() -> Result<()> {
1372 let temp_dir = tempfile::tempdir().unwrap();
1373 let path = temp_dir.path().join("test.db3");
1374
1375 {
1376 let db = Connection::open(&path)?;
1377 let sql = "BEGIN;
1378 CREATE TABLE foo(x INTEGER);
1379 INSERT INTO foo VALUES(42);
1380 END;";
1381 db.execute_batch(sql)?;
1382 }
1383
1384 let path_string = path.to_str().unwrap();
1385 let db = Connection::open(path_string)?;
1386
1387 assert_eq!(42, db.one_column::<i64, _>("SELECT x FROM foo", [])?);
1388 Ok(())
1389 }
1390
1391 #[test]
1392 fn test_open() {
1393 Connection::open_in_memory().unwrap();
1394
1395 let db = checked_memory_handle();
1396 db.close().unwrap();
1397 }
1398
1399 #[cfg_attr(
1400 all(target_family = "wasm", target_os = "unknown"),
1401 ignore = "no filesystem on this platform"
1402 )]
1403 #[test]
1404 fn test_path() -> Result<()> {
1405 let tmp = tempfile::tempdir().unwrap();
1406 let db = Connection::open("")?;
1407 assert_eq!(Some(""), db.path());
1408 let db = Connection::open_in_memory()?;
1409 assert_eq!(Some(""), db.path());
1410 let db = Connection::open("file:dummy.db?mode=memory&cache=shared")?;
1411 assert_eq!(Some(""), db.path());
1412 let path = tmp.path().join("file.db");
1413 let db = Connection::open(path)?;
1414 assert!(db.path().is_some_and(|p| p.ends_with("file.db")));
1415 Ok(())
1416 }
1417
1418 #[test]
1419 fn test_open_failure() {
1420 let filename = "no_such_file.db";
1421 let result = Connection::open_with_flags(filename, OpenFlags::SQLITE_OPEN_READ_ONLY);
1422 let err = result.unwrap_err();
1423 if let Error::SqliteFailure(e, Some(msg)) = err {
1424 assert_eq!(ErrorCode::CannotOpen, e.code);
1425 assert_eq!(ffi::SQLITE_CANTOPEN, e.extended_code);
1426 assert!(
1427 msg.contains(filename),
1428 "error message '{msg}' does not contain '{filename}'"
1429 );
1430 } else {
1431 panic!("SqliteFailure expected");
1432 }
1433 }
1434
1435 #[cfg(unix)]
1436 #[test]
1437 fn test_invalid_unicode_file_names() -> Result<()> {
1438 use std::ffi::OsStr;
1439 use std::fs::File;
1440 use std::os::unix::ffi::OsStrExt;
1441 let temp_dir = tempfile::tempdir().unwrap();
1442
1443 let path = temp_dir.path();
1444 if File::create(path.join(OsStr::from_bytes(&[0xFE]))).is_err() {
1445 return Ok(());
1447 }
1448 let db_path = path.join(OsStr::from_bytes(&[0xFF]));
1449 {
1450 let db = Connection::open(&db_path)?;
1451 let sql = "BEGIN;
1452 CREATE TABLE foo(x INTEGER);
1453 INSERT INTO foo VALUES(42);
1454 END;";
1455 db.execute_batch(sql)?;
1456 }
1457
1458 let db = Connection::open(&db_path)?;
1459
1460 assert_eq!(42, db.one_column::<i64, _>("SELECT x FROM foo", [])?);
1461 Ok(())
1462 }
1463
1464 #[test]
1465 fn test_close_retry() -> Result<()> {
1466 let db = Connection::open_in_memory()?;
1467
1468 let raw_stmt = {
1472 use super::str_to_cstring;
1473 use std::ffi::c_int;
1474 use std::ptr;
1475
1476 let raw_db = db.db.borrow_mut().db;
1477 let sql = "SELECT 1";
1478 let mut raw_stmt: *mut ffi::sqlite3_stmt = ptr::null_mut();
1479 let cstring = str_to_cstring(sql)?;
1480 let rc = unsafe {
1481 ffi::sqlite3_prepare_v2(
1482 raw_db,
1483 cstring.as_ptr(),
1484 (sql.len() + 1) as c_int,
1485 &mut raw_stmt,
1486 ptr::null_mut(),
1487 )
1488 };
1489 assert_eq!(rc, ffi::SQLITE_OK);
1490 raw_stmt
1491 };
1492
1493 let (db, _) = db.close().unwrap_err();
1496 let (db, _) = db.close().unwrap_err();
1497 let (db, _) = db.close().unwrap_err();
1498
1499 assert_eq!(ffi::SQLITE_OK, unsafe { ffi::sqlite3_finalize(raw_stmt) });
1501
1502 db.close().unwrap();
1503 Ok(())
1504 }
1505
1506 #[test]
1507 fn test_open_with_flags() {
1508 for bad_flags in &[
1509 OpenFlags::empty(),
1510 OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_READ_WRITE,
1511 OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_CREATE,
1512 ] {
1513 Connection::open_in_memory_with_flags(*bad_flags).unwrap_err();
1514 }
1515 }
1516
1517 #[test]
1518 fn test_execute_batch() -> Result<()> {
1519 let db = Connection::open_in_memory()?;
1520 let sql = "BEGIN;
1521 CREATE TABLE foo(x INTEGER);
1522 INSERT INTO foo VALUES(1);
1523 INSERT INTO foo VALUES(2);
1524 INSERT INTO foo VALUES(3);
1525 INSERT INTO foo VALUES(4);
1526 END;";
1527 db.execute_batch(sql)?;
1528
1529 db.execute_batch("UPDATE foo SET x = 3 WHERE x < 3")?;
1530
1531 db.execute_batch("INVALID SQL").unwrap_err();
1532
1533 db.execute_batch("PRAGMA locking_mode = EXCLUSIVE")?;
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!(3, 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 fn test_execute_multiple() {
1570 let db = checked_memory_handle();
1571 let err = db
1572 .execute(
1573 "CREATE TABLE foo(x INTEGER); CREATE TABLE foo(x INTEGER)",
1574 [],
1575 )
1576 .unwrap_err();
1577 match err {
1578 Error::MultipleStatement => (),
1579 _ => panic!("Unexpected error: {err}"),
1580 }
1581 db.execute("CREATE TABLE t(c); -- bim", [])
1582 .expect("Tail comment should be ignored");
1583 }
1584
1585 #[test]
1586 fn test_prepare_column_names() -> Result<()> {
1587 let db = Connection::open_in_memory()?;
1588 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1589
1590 let stmt = db.prepare("SELECT * FROM foo")?;
1591 assert_eq!(stmt.column_count(), 1);
1592 assert_eq!(stmt.column_names(), vec!["x"]);
1593
1594 let stmt = db.prepare("SELECT x AS a, x AS b FROM foo")?;
1595 assert_eq!(stmt.column_count(), 2);
1596 assert_eq!(stmt.column_names(), vec!["a", "b"]);
1597 Ok(())
1598 }
1599
1600 #[test]
1601 fn test_prepare_execute() -> Result<()> {
1602 let db = Connection::open_in_memory()?;
1603 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1604
1605 let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?1)")?;
1606 assert_eq!(insert_stmt.execute([1i32])?, 1);
1607 assert_eq!(insert_stmt.execute([2i32])?, 1);
1608 assert_eq!(insert_stmt.execute([3i32])?, 1);
1609
1610 assert_eq!(insert_stmt.execute(["hello"])?, 1);
1611 assert_eq!(insert_stmt.execute(["goodbye"])?, 1);
1612 assert_eq!(insert_stmt.execute([types::Null])?, 1);
1613
1614 let mut update_stmt = db.prepare("UPDATE foo SET x=?1 WHERE x<?2")?;
1615 assert_eq!(update_stmt.execute([3i32, 3i32])?, 2);
1616 assert_eq!(update_stmt.execute([3i32, 3i32])?, 0);
1617 assert_eq!(update_stmt.execute([8i32, 8i32])?, 3);
1618 Ok(())
1619 }
1620
1621 #[test]
1622 fn test_prepare_query() -> Result<()> {
1623 let db = Connection::open_in_memory()?;
1624 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1625
1626 let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?1)")?;
1627 assert_eq!(insert_stmt.execute([1i32])?, 1);
1628 assert_eq!(insert_stmt.execute([2i32])?, 1);
1629 assert_eq!(insert_stmt.execute([3i32])?, 1);
1630
1631 let mut query = db.prepare("SELECT x FROM foo WHERE x < ?1 ORDER BY x DESC")?;
1632 {
1633 let mut rows = query.query([4i32])?;
1634 let mut v = Vec::<i32>::new();
1635
1636 while let Some(row) = rows.next()? {
1637 v.push(row.get(0)?);
1638 }
1639
1640 assert_eq!(v, [3i32, 2, 1]);
1641 }
1642
1643 {
1644 let mut rows = query.query([3i32])?;
1645 let mut v = Vec::<i32>::new();
1646
1647 while let Some(row) = rows.next()? {
1648 v.push(row.get(0)?);
1649 }
1650
1651 assert_eq!(v, [2i32, 1]);
1652 }
1653 Ok(())
1654 }
1655
1656 #[test]
1657 fn test_query_map() -> Result<()> {
1658 let db = Connection::open_in_memory()?;
1659 let sql = "BEGIN;
1660 CREATE TABLE foo(x INTEGER, y TEXT);
1661 INSERT INTO foo VALUES(4, \"hello\");
1662 INSERT INTO foo VALUES(3, \", \");
1663 INSERT INTO foo VALUES(2, \"world\");
1664 INSERT INTO foo VALUES(1, \"!\");
1665 END;";
1666 db.execute_batch(sql)?;
1667
1668 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1669 let results: Result<Vec<String>> = query.query([])?.map(|row| row.get(1)).collect();
1670
1671 assert_eq!(results?.concat(), "hello, world!");
1672 Ok(())
1673 }
1674
1675 #[test]
1676 fn test_query_row() -> Result<()> {
1677 let db = Connection::open_in_memory()?;
1678 let sql = "BEGIN;
1679 CREATE TABLE foo(x INTEGER);
1680 INSERT INTO foo VALUES(1);
1681 INSERT INTO foo VALUES(2);
1682 INSERT INTO foo VALUES(3);
1683 INSERT INTO foo VALUES(4);
1684 END;";
1685 db.execute_batch(sql)?;
1686
1687 assert_eq!(10, db.one_column::<i64, _>("SELECT SUM(x) FROM foo", [])?);
1688
1689 let result: Result<i64> = db.one_column("SELECT x FROM foo WHERE x > 5", []);
1690 match result.unwrap_err() {
1691 Error::QueryReturnedNoRows => (),
1692 err => panic!("Unexpected error {err}"),
1693 }
1694
1695 db.query_row("NOT A PROPER QUERY; test123", [], |_| Ok(()))
1696 .unwrap_err();
1697
1698 db.query_row("SELECT 1; SELECT 2;", [], |_| Ok(()))
1699 .unwrap_err();
1700
1701 Ok(())
1702 }
1703
1704 #[test]
1705 fn test_optional() -> Result<()> {
1706 let db = Connection::open_in_memory()?;
1707
1708 let result: Result<i64> = db.one_column("SELECT 1 WHERE 0 <> 0", []);
1709 let result = result.optional();
1710 match result? {
1711 None => (),
1712 _ => panic!("Unexpected result"),
1713 }
1714
1715 let result: Result<i64> = db.one_column("SELECT 1 WHERE 0 == 0", []);
1716 let result = result.optional();
1717 match result? {
1718 Some(1) => (),
1719 _ => panic!("Unexpected result"),
1720 }
1721
1722 let bad_query_result: Result<i64> = db.one_column("NOT A PROPER QUERY", []);
1723 let bad_query_result = bad_query_result.optional();
1724 bad_query_result.unwrap_err();
1725 Ok(())
1726 }
1727
1728 #[test]
1729 fn test_pragma_query_row() -> Result<()> {
1730 let db = Connection::open_in_memory()?;
1731 assert_eq!(
1732 "memory",
1733 db.one_column::<String, _>("PRAGMA journal_mode", [])?
1734 );
1735 let mode = db.one_column::<String, _>("PRAGMA journal_mode=off", [])?;
1736 if cfg!(feature = "bundled") {
1737 assert_eq!(mode, "off");
1738 } else {
1739 assert!(mode == "memory" || mode == "off", "Got mode {mode:?}");
1751 }
1752
1753 Ok(())
1754 }
1755
1756 #[test]
1757 fn test_prepare_failures() -> Result<()> {
1758 let db = Connection::open_in_memory()?;
1759 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1760
1761 let err = db.prepare("SELECT * FROM does_not_exist").unwrap_err();
1762 assert!(format!("{err}").contains("does_not_exist"));
1763 Ok(())
1764 }
1765
1766 #[test]
1767 fn test_last_insert_rowid() -> Result<()> {
1768 let db = Connection::open_in_memory()?;
1769 db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)")?;
1770 db.execute_batch("INSERT INTO foo DEFAULT VALUES")?;
1771
1772 assert_eq!(db.last_insert_rowid(), 1);
1773
1774 let mut stmt = db.prepare("INSERT INTO foo DEFAULT VALUES")?;
1775 for _ in 0i32..9 {
1776 stmt.execute([])?;
1777 }
1778 assert_eq!(db.last_insert_rowid(), 10);
1779 Ok(())
1780 }
1781
1782 #[test]
1783 fn test_total_changes() -> Result<()> {
1784 let db = Connection::open_in_memory()?;
1785 let sql = "CREATE TABLE foo(x INTEGER PRIMARY KEY, value TEXT default '' NOT NULL,
1786 desc TEXT default '');
1787 CREATE VIEW foo_bar AS SELECT x, desc FROM foo WHERE value = 'bar';
1788 CREATE TRIGGER INSERT_FOOBAR
1789 INSTEAD OF INSERT
1790 ON foo_bar
1791 BEGIN
1792 INSERT INTO foo VALUES(new.x, 'bar', new.desc);
1793 END;";
1794 db.execute_batch(sql)?;
1795 let total_changes_before = db.total_changes();
1796 let changes = db
1797 .prepare("INSERT INTO foo_bar VALUES(null, 'baz');")?
1798 .execute([])?;
1799 let total_changes_after = db.total_changes();
1800 assert_eq!(changes, 0);
1801 assert_eq!(total_changes_after - total_changes_before, 1);
1802 Ok(())
1803 }
1804
1805 #[test]
1806 fn test_is_autocommit() -> Result<()> {
1807 let db = Connection::open_in_memory()?;
1808 assert!(
1809 db.is_autocommit(),
1810 "autocommit expected to be active by default"
1811 );
1812 Ok(())
1813 }
1814
1815 #[test]
1816 fn test_is_busy() -> Result<()> {
1817 let db = Connection::open_in_memory()?;
1818 assert!(!db.is_busy());
1819 let mut stmt = db.prepare("PRAGMA schema_version")?;
1820 assert!(!db.is_busy());
1821 {
1822 let mut rows = stmt.query([])?;
1823 assert!(!db.is_busy());
1824 let row = rows.next()?;
1825 assert!(db.is_busy());
1826 assert!(row.is_some());
1827 }
1828 assert!(!db.is_busy());
1829 Ok(())
1830 }
1831
1832 #[test]
1833 fn test_statement_debugging() -> Result<()> {
1834 let db = Connection::open_in_memory()?;
1835 let query = "SELECT 12345";
1836 let stmt = db.prepare(query)?;
1837
1838 assert!(format!("{stmt:?}").contains(query));
1839 Ok(())
1840 }
1841
1842 #[test]
1843 fn test_notnull_constraint_error() -> Result<()> {
1844 let db = Connection::open_in_memory()?;
1845 db.execute_batch("CREATE TABLE foo(x NOT NULL)")?;
1846
1847 let result = db.execute("INSERT INTO foo (x) VALUES (NULL)", []);
1848
1849 match result.unwrap_err() {
1850 Error::SqliteFailure(err, _) => {
1851 assert_eq!(err.code, ErrorCode::ConstraintViolation);
1852 assert_eq!(err.extended_code, ffi::SQLITE_CONSTRAINT_NOTNULL);
1853 }
1854 err => panic!("Unexpected error {err}"),
1855 }
1856 Ok(())
1857 }
1858
1859 #[test]
1860 fn test_version_string() {
1861 let n = version_number();
1862 let major = n / 1_000_000;
1863 let minor = (n % 1_000_000) / 1_000;
1864 let patch = n % 1_000;
1865
1866 assert!(version().contains(&format!("{major}.{minor}.{patch}")));
1867 }
1868
1869 #[test]
1870 #[cfg(feature = "functions")]
1871 fn test_interrupt() -> Result<()> {
1872 let db = Connection::open_in_memory()?;
1873
1874 let interrupt_handle = db.get_interrupt_handle();
1875
1876 db.create_scalar_function(
1877 "interrupt",
1878 0,
1879 functions::FunctionFlags::default(),
1880 move |_| {
1881 interrupt_handle.interrupt();
1882 Ok(0)
1883 },
1884 )?;
1885
1886 let mut stmt =
1887 db.prepare("SELECT interrupt() FROM (SELECT 1 UNION SELECT 2 UNION SELECT 3)")?;
1888
1889 let result: Result<Vec<i32>> = stmt.query([])?.map(|r| r.get(0)).collect();
1890
1891 assert_eq!(
1892 result.unwrap_err().sqlite_error_code(),
1893 Some(ErrorCode::OperationInterrupted)
1894 );
1895 Ok(())
1896 }
1897
1898 #[test]
1899 fn test_interrupt_close() {
1900 let db = checked_memory_handle();
1901 let handle = db.get_interrupt_handle();
1902 handle.interrupt();
1903 db.close().unwrap();
1904 handle.interrupt();
1905
1906 let db_guard = handle.db_lock.lock().unwrap();
1908 assert!(db_guard.is_null());
1909 }
1913
1914 #[test]
1915 fn test_get_raw() -> Result<()> {
1916 let db = Connection::open_in_memory()?;
1917 db.execute_batch("CREATE TABLE foo(i, x);")?;
1918 let vals = ["foobar", "1234", "qwerty"];
1919 let mut insert_stmt = db.prepare("INSERT INTO foo(i, x) VALUES(?1, ?2)")?;
1920 for (i, v) in vals.iter().enumerate() {
1921 let i_to_insert = i as i64;
1922 assert_eq!(insert_stmt.execute(params![i_to_insert, v])?, 1);
1923 }
1924
1925 let mut query = db.prepare("SELECT i, x FROM foo")?;
1926 let mut rows = query.query([])?;
1927
1928 while let Some(row) = rows.next()? {
1929 let i = row.get_ref(0)?.as_i64()?;
1930 let expect = vals[i as usize];
1931 let x = row.get_ref("x")?.as_str()?;
1932 assert_eq!(x, expect);
1933 }
1934
1935 let mut query = db.prepare("SELECT x FROM foo")?;
1936 let rows = query.query_map([], |row| {
1937 let x = row.get_ref(0)?.as_str()?; Ok(x[..].to_owned())
1939 })?;
1940
1941 for (i, row) in rows.enumerate() {
1942 assert_eq!(row?, vals[i]);
1943 }
1944 Ok(())
1945 }
1946
1947 #[test]
1948 fn test_from_handle() -> Result<()> {
1949 let db = Connection::open_in_memory()?;
1950 let handle = unsafe { db.handle() };
1951 {
1952 let db = unsafe { Connection::from_handle(handle) }?;
1953 db.execute_batch("PRAGMA VACUUM")?;
1954 }
1955 db.close().unwrap();
1956 Ok(())
1957 }
1958
1959 #[test]
1960 fn test_from_handle_owned() -> Result<()> {
1961 let mut handle: *mut ffi::sqlite3 = std::ptr::null_mut();
1962 let r = unsafe { ffi::sqlite3_open(c":memory:".as_ptr(), &mut handle) };
1963 assert_eq!(r, ffi::SQLITE_OK);
1964 let db = unsafe { Connection::from_handle_owned(handle) }?;
1965 db.execute_batch("PRAGMA VACUUM")?;
1966 Ok(())
1967 }
1968
1969 mod query_and_then_tests {
1970 #[cfg(all(target_family = "wasm", target_os = "unknown"))]
1971 use wasm_bindgen_test::wasm_bindgen_test as test;
1972
1973 use super::*;
1974
1975 #[derive(Debug)]
1976 enum CustomError {
1977 SomeError,
1978 Sqlite(Error),
1979 }
1980
1981 impl fmt::Display for CustomError {
1982 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1983 match *self {
1984 Self::SomeError => write!(f, "my custom error"),
1985 Self::Sqlite(ref se) => write!(f, "my custom error: {se}"),
1986 }
1987 }
1988 }
1989
1990 impl StdError for CustomError {
1991 fn description(&self) -> &str {
1992 "my custom error"
1993 }
1994
1995 fn cause(&self) -> Option<&dyn StdError> {
1996 match *self {
1997 Self::SomeError => None,
1998 Self::Sqlite(ref se) => Some(se),
1999 }
2000 }
2001 }
2002
2003 impl From<Error> for CustomError {
2004 fn from(se: Error) -> Self {
2005 Self::Sqlite(se)
2006 }
2007 }
2008
2009 type CustomResult<T> = Result<T, CustomError>;
2010
2011 #[test]
2012 fn test_query_and_then() -> Result<()> {
2013 let db = Connection::open_in_memory()?;
2014 let sql = "BEGIN;
2015 CREATE TABLE foo(x INTEGER, y TEXT);
2016 INSERT INTO foo VALUES(4, \"hello\");
2017 INSERT INTO foo VALUES(3, \", \");
2018 INSERT INTO foo VALUES(2, \"world\");
2019 INSERT INTO foo VALUES(1, \"!\");
2020 END;";
2021 db.execute_batch(sql)?;
2022
2023 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
2024 let results: Result<Vec<String>> =
2025 query.query_and_then([], |row| row.get(1))?.collect();
2026
2027 assert_eq!(results?.concat(), "hello, world!");
2028 Ok(())
2029 }
2030
2031 #[test]
2032 fn test_query_and_then_fails() -> Result<()> {
2033 let db = Connection::open_in_memory()?;
2034 let sql = "BEGIN;
2035 CREATE TABLE foo(x INTEGER, y TEXT);
2036 INSERT INTO foo VALUES(4, \"hello\");
2037 INSERT INTO foo VALUES(3, \", \");
2038 INSERT INTO foo VALUES(2, \"world\");
2039 INSERT INTO foo VALUES(1, \"!\");
2040 END;";
2041 db.execute_batch(sql)?;
2042
2043 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
2044 let bad_type: Result<Vec<f64>> = query.query_and_then([], |row| row.get(1))?.collect();
2045
2046 match bad_type.unwrap_err() {
2047 Error::InvalidColumnType(..) => (),
2048 err => panic!("Unexpected error {err}"),
2049 }
2050
2051 let bad_idx: Result<Vec<String>> =
2052 query.query_and_then([], |row| row.get(3))?.collect();
2053
2054 match bad_idx.unwrap_err() {
2055 Error::InvalidColumnIndex(_) => (),
2056 err => panic!("Unexpected error {err}"),
2057 }
2058 Ok(())
2059 }
2060
2061 #[test]
2062 fn test_query_and_then_custom_error() -> CustomResult<()> {
2063 let db = Connection::open_in_memory()?;
2064 let sql = "BEGIN;
2065 CREATE TABLE foo(x INTEGER, y TEXT);
2066 INSERT INTO foo VALUES(4, \"hello\");
2067 INSERT INTO foo VALUES(3, \", \");
2068 INSERT INTO foo VALUES(2, \"world\");
2069 INSERT INTO foo VALUES(1, \"!\");
2070 END;";
2071 db.execute_batch(sql)?;
2072
2073 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
2074 let results: CustomResult<Vec<String>> = query
2075 .query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite))?
2076 .collect();
2077
2078 assert_eq!(results?.concat(), "hello, world!");
2079 Ok(())
2080 }
2081
2082 #[test]
2083 fn test_query_and_then_custom_error_fails() -> Result<()> {
2084 let db = Connection::open_in_memory()?;
2085 let sql = "BEGIN;
2086 CREATE TABLE foo(x INTEGER, y TEXT);
2087 INSERT INTO foo VALUES(4, \"hello\");
2088 INSERT INTO foo VALUES(3, \", \");
2089 INSERT INTO foo VALUES(2, \"world\");
2090 INSERT INTO foo VALUES(1, \"!\");
2091 END;";
2092 db.execute_batch(sql)?;
2093
2094 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
2095 let bad_type: CustomResult<Vec<f64>> = query
2096 .query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite))?
2097 .collect();
2098
2099 match bad_type.unwrap_err() {
2100 CustomError::Sqlite(Error::InvalidColumnType(..)) => (),
2101 err => panic!("Unexpected error {err}"),
2102 }
2103
2104 let bad_idx: CustomResult<Vec<String>> = query
2105 .query_and_then([], |row| row.get(3).map_err(CustomError::Sqlite))?
2106 .collect();
2107
2108 match bad_idx.unwrap_err() {
2109 CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
2110 err => panic!("Unexpected error {err}"),
2111 }
2112
2113 let non_sqlite_err: CustomResult<Vec<String>> = query
2114 .query_and_then([], |_| Err(CustomError::SomeError))?
2115 .collect();
2116
2117 match non_sqlite_err.unwrap_err() {
2118 CustomError::SomeError => (),
2119 err => panic!("Unexpected error {err}"),
2120 }
2121 Ok(())
2122 }
2123
2124 #[test]
2125 fn test_query_row_and_then_custom_error() -> CustomResult<()> {
2126 let db = Connection::open_in_memory()?;
2127 let sql = "BEGIN;
2128 CREATE TABLE foo(x INTEGER, y TEXT);
2129 INSERT INTO foo VALUES(4, \"hello\");
2130 END;";
2131 db.execute_batch(sql)?;
2132
2133 let query = "SELECT x, y FROM foo ORDER BY x DESC";
2134 let results: CustomResult<String> =
2135 db.query_row_and_then(query, [], |row| row.get(1).map_err(CustomError::Sqlite));
2136
2137 assert_eq!(results?, "hello");
2138 Ok(())
2139 }
2140
2141 #[test]
2142 fn test_query_row_and_then_custom_error_fails() -> Result<()> {
2143 let db = Connection::open_in_memory()?;
2144 let sql = "BEGIN;
2145 CREATE TABLE foo(x INTEGER, y TEXT);
2146 INSERT INTO foo VALUES(4, \"hello\");
2147 END;";
2148 db.execute_batch(sql)?;
2149
2150 let query = "SELECT x, y FROM foo ORDER BY x DESC";
2151 let bad_type: CustomResult<f64> =
2152 db.query_row_and_then(query, [], |row| row.get(1).map_err(CustomError::Sqlite));
2153
2154 match bad_type.unwrap_err() {
2155 CustomError::Sqlite(Error::InvalidColumnType(..)) => (),
2156 err => panic!("Unexpected error {err}"),
2157 }
2158
2159 let bad_idx: CustomResult<String> =
2160 db.query_row_and_then(query, [], |row| row.get(3).map_err(CustomError::Sqlite));
2161
2162 match bad_idx.unwrap_err() {
2163 CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
2164 err => panic!("Unexpected error {err}"),
2165 }
2166
2167 let non_sqlite_err: CustomResult<String> =
2168 db.query_row_and_then(query, [], |_| Err(CustomError::SomeError));
2169
2170 match non_sqlite_err.unwrap_err() {
2171 CustomError::SomeError => (),
2172 err => panic!("Unexpected error {err}"),
2173 }
2174 Ok(())
2175 }
2176 }
2177
2178 #[test]
2179 fn test_dynamic() -> Result<()> {
2180 let db = Connection::open_in_memory()?;
2181 let sql = "BEGIN;
2182 CREATE TABLE foo(x INTEGER, y TEXT);
2183 INSERT INTO foo VALUES(4, \"hello\");
2184 END;";
2185 db.execute_batch(sql)?;
2186
2187 db.query_row("SELECT * FROM foo", [], |r| {
2188 assert_eq!(2, r.as_ref().column_count());
2189 Ok(())
2190 })
2191 }
2192 #[test]
2193 fn test_dyn_box() -> Result<()> {
2194 let db = Connection::open_in_memory()?;
2195 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
2196 let b: Box<dyn ToSql> = Box::new(5);
2197 db.execute("INSERT INTO foo VALUES(?1)", [b])?;
2198 db.query_row("SELECT x FROM foo", [], |r| {
2199 assert_eq!(5, r.get_unwrap::<_, i32>(0));
2200 Ok(())
2201 })
2202 }
2203
2204 #[test]
2205 fn test_params() -> Result<()> {
2206 let db = Connection::open_in_memory()?;
2207 db.query_row(
2208 "SELECT
2209 ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10,
2210 ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19, ?20,
2211 ?21, ?22, ?23, ?24, ?25, ?26, ?27, ?28, ?29, ?30,
2212 ?31, ?32, ?33, ?34;",
2213 params![
2214 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,
2215 1, 1, 1, 1, 1, 1,
2216 ],
2217 |r| {
2218 assert_eq!(1, r.get_unwrap::<_, i32>(0));
2219 Ok(())
2220 },
2221 )
2222 }
2223
2224 #[test]
2225 fn test_alter_table() -> Result<()> {
2226 let db = Connection::open_in_memory()?;
2227 db.execute_batch("CREATE TABLE x(t);")?;
2228 db.execute("ALTER TABLE x RENAME TO y;", [])?;
2230 Ok(())
2231 }
2232
2233 #[test]
2234 fn test_batch() -> Result<()> {
2235 let db = Connection::open_in_memory()?;
2236 let sql = r"
2237 CREATE TABLE tbl1 (col);
2238 CREATE TABLE tbl2 (col);
2239 ";
2240 let mut batch = Batch::new(&db, sql);
2241 while let Some(mut stmt) = batch.next()? {
2242 stmt.execute([])?;
2243 }
2244 Ok(())
2245 }
2246
2247 #[test]
2248 fn test_invalid_batch() -> Result<()> {
2249 let db = Connection::open_in_memory()?;
2250 let sql = r"
2251 PRAGMA test1;
2252 PRAGMA test2=?;
2253 PRAGMA test3;
2254 ";
2255 let mut batch = Batch::new(&db, sql);
2256 assert!(batch.next().is_ok());
2257 assert!(batch.next().is_err());
2258 assert!(batch.next().is_err());
2259 assert!(Batch::new(&db, sql).count().is_err());
2260 Ok(())
2261 }
2262
2263 #[test]
2264 #[cfg(feature = "modern_sqlite")]
2265 fn test_returning() -> Result<()> {
2266 let db = Connection::open_in_memory()?;
2267 db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)")?;
2268 let row_id =
2269 db.one_column::<i64, _>("INSERT INTO foo DEFAULT VALUES RETURNING ROWID", [])?;
2270 assert_eq!(row_id, 1);
2271 Ok(())
2272 }
2273
2274 #[test]
2275 fn test_cache_flush() -> Result<()> {
2276 let db = Connection::open_in_memory()?;
2277 db.cache_flush()
2278 }
2279
2280 #[test]
2281 fn db_readonly() -> Result<()> {
2282 let db = Connection::open_in_memory()?;
2283 assert!(!db.is_readonly(MAIN_DB)?);
2284 Ok(())
2285 }
2286
2287 #[test]
2288 #[cfg(feature = "rusqlite-macros")]
2289 fn prepare_and_bind() -> Result<()> {
2290 let db = Connection::open_in_memory()?;
2291 let name = "Lisa";
2292 let age = 8;
2293 let mut stmt = prepare_and_bind!(db, "SELECT $name, $age;");
2294 let (v1, v2) = stmt
2295 .raw_query()
2296 .next()
2297 .and_then(|o| o.ok_or(Error::QueryReturnedNoRows))
2298 .and_then(|r| Ok((r.get::<_, String>(0)?, r.get::<_, i64>(1)?)))?;
2299 assert_eq!((v1.as_str(), v2), (name, age));
2300 Ok(())
2301 }
2302
2303 #[test]
2304 #[cfg(feature = "modern_sqlite")]
2305 fn test_db_name() -> Result<()> {
2306 let db = Connection::open_in_memory()?;
2307 assert_eq!(db.db_name(0)?, "main");
2308 assert_eq!(db.db_name(1)?, "temp");
2309 assert_eq!(db.db_name(2), Err(Error::InvalidDatabaseIndex(2)));
2310 db.execute_batch("ATTACH DATABASE ':memory:' AS xyz;")?;
2311 assert_eq!(db.db_name(2)?, "xyz");
2312 Ok(())
2313 }
2314
2315 #[test]
2316 #[cfg(feature = "modern_sqlite")]
2317 fn test_is_interrupted() -> Result<()> {
2318 let db = Connection::open_in_memory()?;
2319 assert!(!db.is_interrupted());
2320 db.get_interrupt_handle().interrupt();
2321 assert!(db.is_interrupted());
2322 Ok(())
2323 }
2324
2325 #[test]
2326 fn release_memory() -> Result<()> {
2327 let db = Connection::open_in_memory()?;
2328 db.release_memory()
2329 }
2330}