1#![allow(clippy::all)]
2#![warn(missing_docs)]
56#![cfg_attr(docsrs, feature(doc_cfg))]
57
58pub use libsql_ffi as ffi;
59
60use std::cell::RefCell;
61use std::default::Default;
62use std::ffi::{CStr, CString};
63use std::fmt;
64use std::os::raw::{c_char, c_int};
65
66use std::path::Path;
67use std::result;
68use std::str;
69use std::sync::atomic::Ordering;
70use std::sync::{Arc, Mutex};
71
72use crate::cache::StatementCache;
73use crate::inner_connection::{InnerConnection, BYPASS_SQLITE_INIT};
74use crate::raw_statement::RawStatement;
75use crate::types::ValueRef;
76
77pub use crate::cache::CachedStatement;
78pub use crate::column::Column;
79pub use crate::error::Error;
80pub use crate::ffi::ErrorCode;
81#[cfg(feature = "load_extension")]
82pub use crate::load_extension_guard::LoadExtensionGuard;
83pub use crate::params::{params_from_iter, Params, ParamsFromIter};
84pub use crate::row::{AndThenRows, Map, MappedRows, Row, RowIndex, Rows};
85pub use crate::statement::{Statement, StatementStatus};
86#[cfg(feature = "modern_sqlite")]
87pub use crate::transaction::TransactionState;
88pub use crate::transaction::{DropBehavior, Savepoint, Transaction, TransactionBehavior};
89pub use crate::types::ToSql;
90pub use crate::version::*;
91
92mod error;
93
94#[cfg(feature = "backup")]
95#[cfg_attr(docsrs, doc(cfg(feature = "backup")))]
96pub mod backup;
97#[cfg(feature = "blob")]
98#[cfg_attr(docsrs, doc(cfg(feature = "blob")))]
99pub mod blob;
100mod busy;
101mod cache;
102#[cfg(feature = "collation")]
103#[cfg_attr(docsrs, doc(cfg(feature = "collation")))]
104mod collation;
105mod column;
106pub mod config;
107#[cfg(any(feature = "functions", feature = "vtab"))]
108mod context;
109#[cfg(feature = "functions")]
110#[cfg_attr(docsrs, doc(cfg(feature = "functions")))]
111pub mod functions;
112#[cfg(feature = "hooks")]
113#[cfg_attr(docsrs, doc(cfg(feature = "hooks")))]
114pub mod hooks;
115mod inner_connection;
116#[cfg(feature = "limits")]
117#[cfg_attr(docsrs, doc(cfg(feature = "limits")))]
118pub mod limits;
119#[cfg(feature = "load_extension")]
120mod load_extension_guard;
121mod params;
122mod pragma;
123mod raw_statement;
124mod row;
125#[cfg(feature = "session")]
126#[cfg_attr(docsrs, doc(cfg(feature = "session")))]
127pub mod session;
128mod statement;
129#[cfg(feature = "trace")]
130#[cfg_attr(docsrs, doc(cfg(feature = "trace")))]
131pub mod trace;
132mod transaction;
133pub mod types;
134#[cfg(feature = "unlock_notify")]
135mod unlock_notify;
136mod version;
137#[cfg(feature = "vtab")]
138#[cfg_attr(docsrs, doc(cfg(feature = "vtab")))]
139pub mod vtab;
140
141pub(crate) mod util;
142pub(crate) use util::SmallCString;
143
144const STATEMENT_CACHE_DEFAULT_CAPACITY: usize = 16;
146
147#[macro_export]
170macro_rules! params {
171 () => {
172 &[] as &[&dyn $crate::ToSql]
173 };
174 ($($param:expr),+ $(,)?) => {
175 &[$(&$param as &dyn $crate::ToSql),+] as &[&dyn $crate::ToSql]
176 };
177}
178
179#[macro_export]
207macro_rules! named_params {
208 () => {
209 &[] as &[(&str, &dyn $crate::ToSql)]
210 };
211 ($($param_name:literal: $param_val:expr),+ $(,)?) => {
214 &[$(($param_name, &$param_val as &dyn $crate::ToSql)),+] as &[(&str, &dyn $crate::ToSql)]
215 };
216}
217
218pub type Result<T, E = Error> = result::Result<T, E>;
220
221pub trait OptionalExtension<T> {
223 fn optional(self) -> Result<Option<T>>;
229}
230
231impl<T> OptionalExtension<T> for Result<T> {
232 fn optional(self) -> Result<Option<T>> {
233 match self {
234 Ok(value) => Ok(Some(value)),
235 Err(Error::QueryReturnedNoRows) => Ok(None),
236 Err(e) => Err(e),
237 }
238 }
239}
240
241unsafe fn errmsg_to_string(errmsg: *const c_char) -> String {
242 let c_slice = CStr::from_ptr(errmsg).to_bytes();
243 String::from_utf8_lossy(c_slice).into_owned()
244}
245
246fn str_to_cstring(s: &str) -> Result<SmallCString> {
247 Ok(SmallCString::new(s)?)
248}
249
250fn str_for_sqlite(s: &[u8]) -> Result<(*const c_char, c_int, ffi::sqlite3_destructor_type)> {
257 let len = len_as_c_int(s.len())?;
258 let (ptr, dtor_info) = if len != 0 {
259 (s.as_ptr().cast::<c_char>(), ffi::SQLITE_TRANSIENT())
260 } else {
261 ("".as_ptr().cast::<c_char>(), ffi::SQLITE_STATIC())
263 };
264 Ok((ptr, len, dtor_info))
265}
266
267fn len_as_c_int(len: usize) -> Result<c_int> {
270 if len >= (c_int::MAX as usize) {
271 Err(Error::SqliteFailure(
272 ffi::Error::new(ffi::SQLITE_TOOBIG),
273 None,
274 ))
275 } else {
276 Ok(len as c_int)
277 }
278}
279
280#[cfg(unix)]
281fn path_to_cstring(p: &Path) -> Result<CString> {
282 use std::os::unix::ffi::OsStrExt;
283 Ok(CString::new(p.as_os_str().as_bytes())?)
284}
285
286#[cfg(not(unix))]
287fn path_to_cstring(p: &Path) -> Result<CString> {
288 let s = p.to_str().ok_or_else(|| Error::InvalidPath(p.to_owned()))?;
289 Ok(CString::new(s)?)
290}
291
292#[derive(Copy, Clone, Debug)]
294pub enum DatabaseName<'a> {
295 Main,
297
298 Temp,
300
301 Attached(&'a str),
303}
304
305pub const MAIN_DB: DatabaseName<'static> = DatabaseName::Main;
307
308pub const TEMP_DB: DatabaseName<'static> = DatabaseName::Temp;
310
311impl DatabaseName<'_> {
314 #[inline]
315 fn as_cstring(&self) -> Result<SmallCString> {
316 use self::DatabaseName::{Attached, Main, Temp};
317 match *self {
318 Main => str_to_cstring("main"),
319 Temp => str_to_cstring("temp"),
320 Attached(s) => str_to_cstring(s),
321 }
322 }
323}
324
325pub struct Connection {
327 db: RefCell<InnerConnection>,
328 cache: StatementCache,
329}
330
331unsafe impl Send for Connection {}
332
333impl Drop for Connection {
334 #[inline]
335 fn drop(&mut self) {
336 self.flush_prepared_statement_cache();
337 }
338}
339
340impl Connection {
341 #[inline]
394 pub fn open<P: AsRef<Path>>(path: P) -> Result<Connection> {
395 let flags = OpenFlags::default();
396 Connection::open_with_flags(path, flags)
397 }
398
399 #[inline]
405 pub fn open_in_memory() -> Result<Connection> {
406 let flags = OpenFlags::default();
407 Connection::open_in_memory_with_flags(flags)
408 }
409
410 #[inline]
420 pub fn open_with_flags<P: AsRef<Path>>(path: P, flags: OpenFlags) -> Result<Connection> {
421 let c_path = path_to_cstring(path.as_ref())?;
422 InnerConnection::open_with_flags(
423 &c_path,
424 flags,
425 None,
426 #[cfg(feature = "libsql-experimental")]
427 None,
428 )
429 .map(|db| Connection {
430 db: RefCell::new(db),
431 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
432 })
433 }
434
435 #[inline]
446 pub fn open_with_flags_and_vfs<P: AsRef<Path>>(
447 path: P,
448 flags: OpenFlags,
449 vfs: &str,
450 ) -> Result<Connection> {
451 let c_path = path_to_cstring(path.as_ref())?;
452 let c_vfs = str_to_cstring(vfs)?;
453 InnerConnection::open_with_flags(
454 &c_path,
455 flags,
456 Some(&c_vfs),
457 #[cfg(feature = "libsql-experimental")]
458 None,
459 )
460 .map(|db| Connection {
461 db: RefCell::new(db),
462 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
463 })
464 }
465
466 #[inline]
475 #[cfg(feature = "libsql-experimental")]
476 pub fn open_with_flags_and_wal<P: AsRef<Path>>(
477 path: P,
478 flags: OpenFlags,
479 wal_manager: libsql_ffi::libsql_wal_manager,
480 ) -> Result<Connection> {
481 let c_path = path_to_cstring(path.as_ref())?;
482 InnerConnection::open_with_flags(&c_path, flags, None, Some(wal_manager)).map(|db| {
483 Connection {
484 db: RefCell::new(db),
485 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
486 }
487 })
488 }
489
490 #[inline]
499 #[cfg(feature = "libsql-experimental")]
500 pub fn open_with_flags_vfs_and_wal<P: AsRef<Path>>(
501 path: P,
502 flags: OpenFlags,
503 vfs: &str,
504 wal_manager: ffi::libsql_wal_manager,
505 ) -> Result<Connection> {
506 let c_path = path_to_cstring(path.as_ref())?;
507 let c_vfs = str_to_cstring(vfs)?;
508 InnerConnection::open_with_flags(&c_path, flags, Some(&c_vfs), Some(wal_manager)).map(
509 |db| Connection {
510 db: RefCell::new(db),
511 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
512 },
513 )
514 }
515
516 #[inline]
525 pub fn open_in_memory_with_flags(flags: OpenFlags) -> Result<Connection> {
526 Connection::open_with_flags(":memory:", flags)
527 }
528
529 #[inline]
540 pub fn open_in_memory_with_flags_and_vfs(flags: OpenFlags, vfs: &str) -> Result<Connection> {
541 Connection::open_with_flags_and_vfs(":memory:", flags, vfs)
542 }
543
544 pub fn execute_batch(&self, sql: &str) -> Result<()> {
566 let mut sql = sql;
567 while !sql.is_empty() {
568 let stmt = self.prepare(sql)?;
569 if !stmt.stmt.is_null() && stmt.step()? && cfg!(feature = "extra_check") {
570 return Err(Error::ExecuteReturnedResults);
572 }
573 let tail = stmt.stmt.tail();
574 if tail == 0 || tail >= sql.len() {
575 break;
576 }
577 sql = &sql[tail..];
578 }
579 Ok(())
580 }
581
582 #[inline]
633 pub fn execute<P: Params>(&self, sql: &str, params: P) -> Result<usize> {
634 self.prepare(sql)
635 .and_then(|mut stmt| stmt.check_no_tail().and_then(|_| stmt.execute(params)))
636 }
637
638 #[inline]
646 pub fn path(&self) -> Option<&str> {
647 unsafe {
648 let db = self.handle();
649 let db_name = DatabaseName::Main.as_cstring().unwrap();
650 let db_filename = ffi::sqlite3_db_filename(db, db_name.as_ptr());
651 if db_filename.is_null() {
652 None
653 } else {
654 CStr::from_ptr(db_filename).to_str().ok()
655 }
656 }
657 }
658
659 #[inline]
664 #[cfg(feature = "release_memory")]
665 pub fn release_memory(&self) -> Result<()> {
666 self.db.borrow_mut().release_memory()
667 }
668
669 #[inline]
674 pub fn last_insert_rowid(&self) -> i64 {
675 self.db.borrow_mut().last_insert_rowid()
676 }
677
678 #[inline]
706 pub fn query_row<T, P, F>(&self, sql: &str, params: P, f: F) -> Result<T>
707 where
708 P: Params,
709 F: FnOnce(&Row<'_>) -> Result<T>,
710 {
711 let mut stmt = self.prepare(sql)?;
712 stmt.check_no_tail()?;
713 stmt.query_row(params, f)
714 }
715
716 #[cfg(test)]
718 pub(crate) fn one_column<T: crate::types::FromSql>(&self, sql: &str) -> Result<T> {
719 self.query_row(sql, [], |r| r.get(0))
720 }
721
722 #[inline]
748 pub fn query_row_and_then<T, E, P, F>(&self, sql: &str, params: P, f: F) -> Result<T, E>
749 where
750 P: Params,
751 F: FnOnce(&Row<'_>) -> Result<T, E>,
752 E: From<Error>,
753 {
754 let mut stmt = self.prepare(sql)?;
755 stmt.check_no_tail()?;
756 let mut rows = stmt.query(params)?;
757
758 rows.get_expected_row().map_err(E::from).and_then(f)
759 }
760
761 #[inline]
780 pub fn prepare(&self, sql: &str) -> Result<Statement<'_>> {
781 self.db.borrow_mut().prepare(self, sql)
782 }
783
784 #[inline]
794 pub fn close(self) -> Result<(), (Connection, Error)> {
795 self.flush_prepared_statement_cache();
796 let r = self.db.borrow_mut().close();
797 r.map_err(move |err| (self, err))
798 }
799
800 #[cfg(feature = "load_extension")]
853 #[cfg_attr(docsrs, doc(cfg(feature = "load_extension")))]
854 #[inline]
855 pub unsafe fn load_extension_enable(&self) -> Result<()> {
856 self.db.borrow_mut().enable_load_extension(1)
857 }
858
859 #[cfg(feature = "load_extension")]
867 #[cfg_attr(docsrs, doc(cfg(feature = "load_extension")))]
868 #[inline]
869 pub fn load_extension_disable(&self) -> Result<()> {
870 unsafe { self.db.borrow_mut().enable_load_extension(0) }
872 }
873
874 #[cfg(feature = "load_extension")]
910 #[cfg_attr(docsrs, doc(cfg(feature = "load_extension")))]
911 #[inline]
912 pub unsafe fn load_extension<P: AsRef<Path>>(
913 &self,
914 dylib_path: P,
915 entry_point: Option<&str>,
916 ) -> Result<()> {
917 self.db
918 .borrow_mut()
919 .load_extension(dylib_path.as_ref(), entry_point)
920 }
921
922 #[inline]
936 pub unsafe fn handle(&self) -> *mut ffi::sqlite3 {
937 self.db.borrow().db()
938 }
939
940 #[inline]
949 pub unsafe fn from_handle(db: *mut ffi::sqlite3) -> Result<Connection> {
950 let db = InnerConnection::new(db, false);
951 Ok(Connection {
952 db: RefCell::new(db),
953 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
954 })
955 }
956
957 #[inline]
969 pub unsafe fn from_handle_owned(db: *mut ffi::sqlite3) -> Result<Connection> {
970 let db = InnerConnection::new(db, true);
971 Ok(Connection {
972 db: RefCell::new(db),
973 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
974 })
975 }
976
977 #[inline]
980 pub fn get_interrupt_handle(&self) -> InterruptHandle {
981 self.db.borrow().get_interrupt_handle()
982 }
983
984 #[inline]
985 fn decode_result(&self, code: c_int) -> Result<()> {
986 self.db.borrow().decode_result(code)
987 }
988
989 #[inline]
995 pub fn changes(&self) -> u64 {
996 self.db.borrow().changes()
997 }
998
999 #[inline]
1002 pub fn is_autocommit(&self) -> bool {
1003 self.db.borrow().is_autocommit()
1004 }
1005
1006 #[inline]
1008 pub fn is_busy(&self) -> bool {
1009 self.db.borrow().is_busy()
1010 }
1011
1012 pub fn cache_flush(&self) -> Result<()> {
1014 self.db.borrow_mut().cache_flush()
1015 }
1016
1017 pub fn is_readonly(&self, db_name: DatabaseName<'_>) -> Result<bool> {
1019 self.db.borrow().db_readonly(db_name)
1020 }
1021
1022 #[cfg(feature = "libsql-wasm-experimental")]
1024 pub fn try_initialize_wasm_func_table(&self) -> Result<()> {
1025 self.db.borrow().try_initialize_wasm_func_table()
1026 }
1027}
1028
1029impl fmt::Debug for Connection {
1030 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1031 f.debug_struct("Connection")
1032 .field("path", &self.path())
1033 .finish()
1034 }
1035}
1036
1037#[derive(Debug)]
1055pub struct Batch<'conn, 'sql> {
1056 conn: &'conn Connection,
1057 sql: &'sql str,
1058 tail: usize,
1059}
1060
1061impl<'conn, 'sql> Batch<'conn, 'sql> {
1062 pub fn new(conn: &'conn Connection, sql: &'sql str) -> Batch<'conn, 'sql> {
1064 Batch { conn, sql, tail: 0 }
1065 }
1066
1067 #[allow(clippy::should_implement_trait)] pub fn next(&mut self) -> Result<Option<Statement<'conn>>> {
1072 while self.tail < self.sql.len() {
1073 let sql = &self.sql[self.tail..];
1074 let next = self.conn.prepare(sql)?;
1075 let tail = next.stmt.tail();
1076 if tail == 0 {
1077 self.tail = self.sql.len();
1078 } else {
1079 self.tail += tail;
1080 }
1081 if next.stmt.is_null() {
1082 continue;
1083 }
1084 return Ok(Some(next));
1085 }
1086 Ok(None)
1087 }
1088}
1089
1090impl<'conn> Iterator for Batch<'conn, '_> {
1091 type Item = Result<Statement<'conn>>;
1092
1093 fn next(&mut self) -> Option<Result<Statement<'conn>>> {
1094 self.next().transpose()
1095 }
1096}
1097
1098bitflags::bitflags! {
1099 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1106 #[repr(C)]
1107 pub struct OpenFlags: ::std::os::raw::c_int {
1108 const SQLITE_OPEN_READ_ONLY = ffi::SQLITE_OPEN_READONLY;
1111 const SQLITE_OPEN_READ_WRITE = ffi::SQLITE_OPEN_READWRITE;
1115 const SQLITE_OPEN_CREATE = ffi::SQLITE_OPEN_CREATE;
1117 const SQLITE_OPEN_URI = ffi::SQLITE_OPEN_URI;
1119 const SQLITE_OPEN_MEMORY = ffi::SQLITE_OPEN_MEMORY;
1121 const SQLITE_OPEN_NO_MUTEX = ffi::SQLITE_OPEN_NOMUTEX;
1130 const SQLITE_OPEN_FULL_MUTEX = ffi::SQLITE_OPEN_FULLMUTEX;
1154 const SQLITE_OPEN_SHARED_CACHE = 0x0002_0000;
1161 const SQLITE_OPEN_PRIVATE_CACHE = 0x0004_0000;
1163 const SQLITE_OPEN_NOFOLLOW = 0x0100_0000;
1165 const SQLITE_OPEN_EXRESCODE = 0x0200_0000;
1167 }
1168}
1169
1170impl Default for OpenFlags {
1171 #[inline]
1172 fn default() -> OpenFlags {
1173 OpenFlags::SQLITE_OPEN_READ_WRITE
1176 | OpenFlags::SQLITE_OPEN_CREATE
1177 | OpenFlags::SQLITE_OPEN_NO_MUTEX
1178 | OpenFlags::SQLITE_OPEN_URI
1179 }
1180}
1181
1182pub unsafe fn bypass_sqlite_initialization() {
1202 BYPASS_SQLITE_INIT.store(true, Ordering::Relaxed);
1203}
1204
1205pub struct InterruptHandle {
1207 db_lock: Arc<Mutex<*mut ffi::sqlite3>>,
1208}
1209
1210unsafe impl Send for InterruptHandle {}
1211unsafe impl Sync for InterruptHandle {}
1212
1213impl InterruptHandle {
1214 pub fn interrupt(&self) {
1217 let db_handle = self.db_lock.lock().unwrap();
1218 if !db_handle.is_null() {
1219 unsafe { ffi::sqlite3_interrupt(*db_handle) }
1220 }
1221 }
1222}
1223
1224#[cfg(doctest)]
1225doc_comment::doctest!("../README.md");
1226
1227#[cfg(test)]
1228mod test {
1229 use super::*;
1230 use crate::ffi;
1231 use fallible_iterator::FallibleIterator;
1232 use std::error::Error as StdError;
1233 use std::fmt;
1234
1235 #[allow(
1239 dead_code,
1240 unconditional_recursion,
1241 clippy::extra_unused_type_parameters
1242 )]
1243 fn ensure_send<T: Send>() {
1244 ensure_send::<Connection>();
1245 ensure_send::<InterruptHandle>();
1246 }
1247
1248 #[allow(
1249 dead_code,
1250 unconditional_recursion,
1251 clippy::extra_unused_type_parameters
1252 )]
1253 fn ensure_sync<T: Sync>() {
1254 ensure_sync::<InterruptHandle>();
1255 }
1256
1257 fn checked_memory_handle() -> Connection {
1258 Connection::open_in_memory().unwrap()
1259 }
1260
1261 #[test]
1262 fn test_concurrent_transactions_busy_commit() -> Result<()> {
1263 use std::time::Duration;
1264 let tmp = tempfile::tempdir().unwrap();
1265 let path = tmp.path().join("transactions.db3");
1266
1267 Connection::open(&path)?.execute_batch(
1268 "
1269 BEGIN; CREATE TABLE foo(x INTEGER);
1270 INSERT INTO foo VALUES(42); END;",
1271 )?;
1272
1273 let mut db1 = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_WRITE)?;
1274 let mut db2 = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_ONLY)?;
1275
1276 db1.busy_timeout(Duration::from_millis(0))?;
1277 db2.busy_timeout(Duration::from_millis(0))?;
1278
1279 {
1280 let tx1 = db1.transaction()?;
1281 let tx2 = db2.transaction()?;
1282
1283 tx1.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))?;
1285 tx2.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))?;
1286
1287 tx1.execute("INSERT INTO foo VALUES(?1)", [1])?;
1288 let _ = tx2.execute("INSERT INTO foo VALUES(?1)", [2]);
1289
1290 let _ = tx1.commit();
1291 let _ = tx2.commit();
1292 }
1293
1294 let _ = db1
1295 .transaction()
1296 .expect("commit should have closed transaction");
1297 let _ = db2
1298 .transaction()
1299 .expect("commit should have closed transaction");
1300 Ok(())
1301 }
1302
1303 #[test]
1304 fn test_persistence() -> Result<()> {
1305 let temp_dir = tempfile::tempdir().unwrap();
1306 let path = temp_dir.path().join("test.db3");
1307
1308 {
1309 let db = Connection::open(&path)?;
1310 let sql = "BEGIN;
1311 CREATE TABLE foo(x INTEGER);
1312 INSERT INTO foo VALUES(42);
1313 END;";
1314 db.execute_batch(sql)?;
1315 }
1316
1317 let path_string = path.to_str().unwrap();
1318 let db = Connection::open(path_string)?;
1319 let the_answer: i64 = db.one_column("SELECT x FROM foo")?;
1320
1321 assert_eq!(42i64, the_answer);
1322 Ok(())
1323 }
1324
1325 #[test]
1326 fn test_open() {
1327 Connection::open_in_memory().unwrap();
1328
1329 let db = checked_memory_handle();
1330 db.close().unwrap();
1331 }
1332
1333 #[test]
1334 fn test_path() -> Result<()> {
1335 let tmp = tempfile::tempdir().unwrap();
1336 let db = Connection::open("")?;
1337 assert_eq!(Some(""), db.path());
1338 let db = Connection::open_in_memory()?;
1339 assert_eq!(Some(""), db.path());
1340 let db = Connection::open("file:dummy.db?mode=memory&cache=shared")?;
1341 assert_eq!(Some(""), db.path());
1342 let path = tmp.path().join("file.db");
1343 let db = Connection::open(path)?;
1344 assert!(db.path().map(|p| p.ends_with("file.db")).unwrap_or(false));
1345 Ok(())
1346 }
1347
1348 #[test]
1349 fn test_open_failure() {
1350 let filename = "no_such_file.db";
1351 let result = Connection::open_with_flags(filename, OpenFlags::SQLITE_OPEN_READ_ONLY);
1352 let err = result.unwrap_err();
1353 if let Error::SqliteFailure(e, Some(msg)) = err {
1354 assert_eq!(ErrorCode::CannotOpen, e.code);
1355 assert_eq!(ffi::SQLITE_CANTOPEN, e.extended_code);
1356 assert!(
1357 msg.contains(filename),
1358 "error message '{}' does not contain '{}'",
1359 msg,
1360 filename
1361 );
1362 } else {
1363 panic!("SqliteFailure expected");
1364 }
1365 }
1366
1367 #[cfg(unix)]
1368 #[test]
1369 fn test_invalid_unicode_file_names() -> Result<()> {
1370 use std::ffi::OsStr;
1371 use std::fs::File;
1372 use std::os::unix::ffi::OsStrExt;
1373 let temp_dir = tempfile::tempdir().unwrap();
1374
1375 let path = temp_dir.path();
1376 if File::create(path.join(OsStr::from_bytes(&[0xFE]))).is_err() {
1377 return Ok(());
1379 }
1380 let db_path = path.join(OsStr::from_bytes(&[0xFF]));
1381 {
1382 let db = Connection::open(&db_path)?;
1383 let sql = "BEGIN;
1384 CREATE TABLE foo(x INTEGER);
1385 INSERT INTO foo VALUES(42);
1386 END;";
1387 db.execute_batch(sql)?;
1388 }
1389
1390 let db = Connection::open(&db_path)?;
1391 let the_answer: i64 = db.one_column("SELECT x FROM foo")?;
1392
1393 assert_eq!(42i64, the_answer);
1394 Ok(())
1395 }
1396
1397 #[test]
1398 fn test_close_retry() -> Result<()> {
1399 let db = Connection::open_in_memory()?;
1400
1401 let raw_stmt = {
1405 use super::str_to_cstring;
1406 use std::os::raw::c_int;
1407 use std::ptr;
1408
1409 let raw_db = db.db.borrow_mut().db;
1410 let sql = "SELECT 1";
1411 let mut raw_stmt: *mut ffi::sqlite3_stmt = ptr::null_mut();
1412 let cstring = str_to_cstring(sql)?;
1413 let rc = unsafe {
1414 ffi::sqlite3_prepare_v2(
1415 raw_db,
1416 cstring.as_ptr(),
1417 (sql.len() + 1) as c_int,
1418 &mut raw_stmt,
1419 ptr::null_mut(),
1420 )
1421 };
1422 assert_eq!(rc, ffi::SQLITE_OK);
1423 raw_stmt
1424 };
1425
1426 let (db, _) = db.close().unwrap_err();
1429 let (db, _) = db.close().unwrap_err();
1430 let (db, _) = db.close().unwrap_err();
1431
1432 assert_eq!(ffi::SQLITE_OK, unsafe { ffi::sqlite3_finalize(raw_stmt) });
1434
1435 db.close().unwrap();
1436 Ok(())
1437 }
1438
1439 #[test]
1440 fn test_open_with_flags() {
1441 for bad_flags in &[
1442 OpenFlags::empty(),
1443 OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_READ_WRITE,
1444 OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_CREATE,
1445 ] {
1446 Connection::open_in_memory_with_flags(*bad_flags).unwrap_err();
1447 }
1448 }
1449
1450 #[test]
1451 fn test_execute_batch() -> Result<()> {
1452 let db = Connection::open_in_memory()?;
1453 let sql = "BEGIN;
1454 CREATE TABLE foo(x INTEGER);
1455 INSERT INTO foo VALUES(1);
1456 INSERT INTO foo VALUES(2);
1457 INSERT INTO foo VALUES(3);
1458 INSERT INTO foo VALUES(4);
1459 END;";
1460 db.execute_batch(sql)?;
1461
1462 db.execute_batch("UPDATE foo SET x = 3 WHERE x < 3")?;
1463
1464 db.execute_batch("INVALID SQL").unwrap_err();
1465 Ok(())
1466 }
1467
1468 #[test]
1469 fn test_execute() -> Result<()> {
1470 let db = Connection::open_in_memory()?;
1471 db.execute_batch("CREATE TABLE foo(x INTEGER)")?;
1472
1473 assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?1)", [1i32])?);
1474 assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?1)", [2i32])?);
1475
1476 assert_eq!(3i32, db.one_column::<i32>("SELECT SUM(x) FROM foo")?);
1477 Ok(())
1478 }
1479
1480 #[test]
1481 #[cfg(feature = "extra_check")]
1482 fn test_execute_select() {
1483 let db = checked_memory_handle();
1484 let err = db.execute("SELECT 1 WHERE 1 < ?1", [1i32]).unwrap_err();
1485 assert_eq!(
1486 err,
1487 Error::ExecuteReturnedResults,
1488 "Unexpected error: {}",
1489 err
1490 );
1491 }
1492
1493 #[test]
1494 #[cfg(feature = "extra_check")]
1495 fn test_execute_multiple() {
1496 let db = checked_memory_handle();
1497 let err = db
1498 .execute(
1499 "CREATE TABLE foo(x INTEGER); CREATE TABLE foo(x INTEGER)",
1500 [],
1501 )
1502 .unwrap_err();
1503 match err {
1504 Error::MultipleStatement => (),
1505 _ => panic!("Unexpected error: {}", err),
1506 }
1507 }
1508
1509 #[test]
1510 fn test_prepare_column_names() -> Result<()> {
1511 let db = Connection::open_in_memory()?;
1512 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1513
1514 let stmt = db.prepare("SELECT * FROM foo")?;
1515 assert_eq!(stmt.column_count(), 1);
1516 assert_eq!(stmt.column_names(), vec!["x"]);
1517
1518 let stmt = db.prepare("SELECT x AS a, x AS b FROM foo")?;
1519 assert_eq!(stmt.column_count(), 2);
1520 assert_eq!(stmt.column_names(), vec!["a", "b"]);
1521 Ok(())
1522 }
1523
1524 #[test]
1525 fn test_prepare_execute() -> Result<()> {
1526 let db = Connection::open_in_memory()?;
1527 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1528
1529 let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?1)")?;
1530 assert_eq!(insert_stmt.execute([1i32])?, 1);
1531 assert_eq!(insert_stmt.execute([2i32])?, 1);
1532 assert_eq!(insert_stmt.execute([3i32])?, 1);
1533
1534 assert_eq!(insert_stmt.execute(["hello"])?, 1);
1535 assert_eq!(insert_stmt.execute(["goodbye"])?, 1);
1536 assert_eq!(insert_stmt.execute([types::Null])?, 1);
1537
1538 let mut update_stmt = db.prepare("UPDATE foo SET x=?1 WHERE x<?2")?;
1539 assert_eq!(update_stmt.execute([3i32, 3i32])?, 2);
1540 assert_eq!(update_stmt.execute([3i32, 3i32])?, 0);
1541 assert_eq!(update_stmt.execute([8i32, 8i32])?, 3);
1542 Ok(())
1543 }
1544
1545 #[test]
1546 fn test_prepare_query() -> Result<()> {
1547 let db = Connection::open_in_memory()?;
1548 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1549
1550 let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?1)")?;
1551 assert_eq!(insert_stmt.execute([1i32])?, 1);
1552 assert_eq!(insert_stmt.execute([2i32])?, 1);
1553 assert_eq!(insert_stmt.execute([3i32])?, 1);
1554
1555 let mut query = db.prepare("SELECT x FROM foo WHERE x < ?1 ORDER BY x DESC")?;
1556 {
1557 let mut rows = query.query([4i32])?;
1558 let mut v = Vec::<i32>::new();
1559
1560 while let Some(row) = rows.next()? {
1561 v.push(row.get(0)?);
1562 }
1563
1564 assert_eq!(v, [3i32, 2, 1]);
1565 }
1566
1567 {
1568 let mut rows = query.query([3i32])?;
1569 let mut v = Vec::<i32>::new();
1570
1571 while let Some(row) = rows.next()? {
1572 v.push(row.get(0)?);
1573 }
1574
1575 assert_eq!(v, [2i32, 1]);
1576 }
1577 Ok(())
1578 }
1579
1580 #[test]
1581 fn test_query_map() -> Result<()> {
1582 let db = Connection::open_in_memory()?;
1583 let sql = "BEGIN;
1584 CREATE TABLE foo(x INTEGER, y TEXT);
1585 INSERT INTO foo VALUES(4, 'hello');
1586 INSERT INTO foo VALUES(3, ', ');
1587 INSERT INTO foo VALUES(2, 'world');
1588 INSERT INTO foo VALUES(1, '!');
1589 END;";
1590 db.execute_batch(sql)?;
1591
1592 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1593 let results: Result<Vec<String>> = query.query([])?.map(|row| row.get(1)).collect();
1594
1595 assert_eq!(results?.concat(), "hello, world!");
1596 Ok(())
1597 }
1598
1599 #[test]
1600 fn test_query_row() -> Result<()> {
1601 let db = Connection::open_in_memory()?;
1602 let sql = "BEGIN;
1603 CREATE TABLE foo(x INTEGER);
1604 INSERT INTO foo VALUES(1);
1605 INSERT INTO foo VALUES(2);
1606 INSERT INTO foo VALUES(3);
1607 INSERT INTO foo VALUES(4);
1608 END;";
1609 db.execute_batch(sql)?;
1610
1611 assert_eq!(10i64, db.one_column::<i64>("SELECT SUM(x) FROM foo")?);
1612
1613 let result: Result<i64> = db.one_column("SELECT x FROM foo WHERE x > 5");
1614 match result.unwrap_err() {
1615 Error::QueryReturnedNoRows => (),
1616 err => panic!("Unexpected error {}", err),
1617 }
1618
1619 let bad_query_result = db.query_row("NOT A PROPER QUERY; test123", [], |_| Ok(()));
1620
1621 bad_query_result.unwrap_err();
1622 Ok(())
1623 }
1624
1625 #[test]
1626 fn test_optional() -> Result<()> {
1627 let db = Connection::open_in_memory()?;
1628
1629 let result: Result<i64> = db.one_column("SELECT 1 WHERE 0 <> 0");
1630 let result = result.optional();
1631 match result? {
1632 None => (),
1633 _ => panic!("Unexpected result"),
1634 }
1635
1636 let result: Result<i64> = db.one_column("SELECT 1 WHERE 0 == 0");
1637 let result = result.optional();
1638 match result? {
1639 Some(1) => (),
1640 _ => panic!("Unexpected result"),
1641 }
1642
1643 let bad_query_result: Result<i64> = db.one_column("NOT A PROPER QUERY");
1644 let bad_query_result = bad_query_result.optional();
1645 bad_query_result.unwrap_err();
1646 Ok(())
1647 }
1648
1649 #[test]
1650 fn test_pragma_query_row() -> Result<()> {
1651 let db = Connection::open_in_memory()?;
1652 assert_eq!("memory", db.one_column::<String>("PRAGMA journal_mode")?);
1653 let mode = db.one_column::<String>("PRAGMA journal_mode=off")?;
1654 if cfg!(feature = "bundled") {
1655 assert_eq!(mode, "off");
1656 } else {
1657 assert!(mode == "memory" || mode == "off", "Got mode {:?}", mode);
1669 }
1670
1671 Ok(())
1672 }
1673
1674 #[test]
1675 fn test_prepare_failures() -> Result<()> {
1676 let db = Connection::open_in_memory()?;
1677 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1678
1679 let err = db.prepare("SELECT * FROM does_not_exist").unwrap_err();
1680 assert!(format!("{err}").contains("does_not_exist"));
1681 Ok(())
1682 }
1683
1684 #[test]
1685 fn test_last_insert_rowid() -> Result<()> {
1686 let db = Connection::open_in_memory()?;
1687 db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)")?;
1688 db.execute_batch("INSERT INTO foo DEFAULT VALUES")?;
1689
1690 assert_eq!(db.last_insert_rowid(), 1);
1691
1692 let mut stmt = db.prepare("INSERT INTO foo DEFAULT VALUES")?;
1693 for _ in 0i32..9 {
1694 stmt.execute([])?;
1695 }
1696 assert_eq!(db.last_insert_rowid(), 10);
1697 Ok(())
1698 }
1699
1700 #[test]
1701 fn test_is_autocommit() -> Result<()> {
1702 let db = Connection::open_in_memory()?;
1703 assert!(
1704 db.is_autocommit(),
1705 "autocommit expected to be active by default"
1706 );
1707 Ok(())
1708 }
1709
1710 #[test]
1711 fn test_is_busy() -> Result<()> {
1712 let db = Connection::open_in_memory()?;
1713 assert!(!db.is_busy());
1714 let mut stmt = db.prepare("PRAGMA schema_version")?;
1715 assert!(!db.is_busy());
1716 {
1717 let mut rows = stmt.query([])?;
1718 assert!(!db.is_busy());
1719 let row = rows.next()?;
1720 assert!(db.is_busy());
1721 assert!(row.is_some());
1722 }
1723 assert!(!db.is_busy());
1724 Ok(())
1725 }
1726
1727 #[test]
1728 fn test_statement_debugging() -> Result<()> {
1729 let db = Connection::open_in_memory()?;
1730 let query = "SELECT 12345";
1731 let stmt = db.prepare(query)?;
1732
1733 assert!(format!("{stmt:?}").contains(query));
1734 Ok(())
1735 }
1736
1737 #[test]
1738 fn test_notnull_constraint_error() -> Result<()> {
1739 fn check_extended_code(extended_code: c_int) {
1742 assert_eq!(extended_code, ffi::SQLITE_CONSTRAINT_NOTNULL);
1743 }
1744
1745 let db = Connection::open_in_memory()?;
1746 db.execute_batch("CREATE TABLE foo(x NOT NULL)")?;
1747
1748 let result = db.execute("INSERT INTO foo (x) VALUES (NULL)", []);
1749
1750 match result.unwrap_err() {
1751 Error::SqliteFailure(err, _) => {
1752 assert_eq!(err.code, ErrorCode::ConstraintViolation);
1753 check_extended_code(err.extended_code);
1754 }
1755 err => panic!("Unexpected error {}", err),
1756 }
1757 Ok(())
1758 }
1759
1760 #[test]
1761 fn test_version_string() {
1762 let n = version_number();
1763 let major = n / 1_000_000;
1764 let minor = (n % 1_000_000) / 1_000;
1765 let patch = n % 1_000;
1766
1767 assert!(version().contains(&format!("{major}.{minor}.{patch}")));
1768 }
1769
1770 #[test]
1771 #[cfg(feature = "functions")]
1772 fn test_interrupt() -> Result<()> {
1773 let db = Connection::open_in_memory()?;
1774
1775 let interrupt_handle = db.get_interrupt_handle();
1776
1777 db.create_scalar_function(
1778 "interrupt",
1779 0,
1780 functions::FunctionFlags::default(),
1781 move |_| {
1782 interrupt_handle.interrupt();
1783 Ok(0)
1784 },
1785 )?;
1786
1787 let mut stmt =
1788 db.prepare("SELECT interrupt() FROM (SELECT 1 UNION SELECT 2 UNION SELECT 3)")?;
1789
1790 let result: Result<Vec<i32>> = stmt.query([])?.map(|r| r.get(0)).collect();
1791
1792 assert_eq!(
1793 result.unwrap_err().sqlite_error_code(),
1794 Some(ErrorCode::OperationInterrupted)
1795 );
1796 Ok(())
1797 }
1798
1799 #[test]
1800 fn test_interrupt_close() {
1801 let db = checked_memory_handle();
1802 let handle = db.get_interrupt_handle();
1803 handle.interrupt();
1804 db.close().unwrap();
1805 handle.interrupt();
1806
1807 let db_guard = handle.db_lock.lock().unwrap();
1809 assert!(db_guard.is_null());
1810 }
1814
1815 #[test]
1816 fn test_get_raw() -> Result<()> {
1817 let db = Connection::open_in_memory()?;
1818 db.execute_batch("CREATE TABLE foo(i, x);")?;
1819 let vals = ["foobar", "1234", "qwerty"];
1820 let mut insert_stmt = db.prepare("INSERT INTO foo(i, x) VALUES(?1, ?2)")?;
1821 for (i, v) in vals.iter().enumerate() {
1822 let i_to_insert = i as i64;
1823 assert_eq!(insert_stmt.execute(params![i_to_insert, v])?, 1);
1824 }
1825
1826 let mut query = db.prepare("SELECT i, x FROM foo")?;
1827 let mut rows = query.query([])?;
1828
1829 while let Some(row) = rows.next()? {
1830 let i = row.get_ref(0)?.as_i64()?;
1831 let expect = vals[i as usize];
1832 let x = row.get_ref("x")?.as_str()?;
1833 assert_eq!(x, expect);
1834 }
1835
1836 let mut query = db.prepare("SELECT x FROM foo")?;
1837 let rows = query.query_map([], |row| {
1838 let x = row.get_ref(0)?.as_str()?; Ok(x[..].to_owned())
1840 })?;
1841
1842 for (i, row) in rows.enumerate() {
1843 assert_eq!(row?, vals[i]);
1844 }
1845 Ok(())
1846 }
1847
1848 #[test]
1849 fn test_from_handle() -> Result<()> {
1850 let db = Connection::open_in_memory()?;
1851 let handle = unsafe { db.handle() };
1852 {
1853 let db = unsafe { Connection::from_handle(handle) }?;
1854 db.execute_batch("PRAGMA VACUUM")?;
1855 }
1856 db.close().unwrap();
1857 Ok(())
1858 }
1859
1860 #[test]
1861 fn test_from_handle_owned() -> Result<()> {
1862 let mut handle: *mut ffi::sqlite3 = std::ptr::null_mut();
1863 let r = unsafe { ffi::sqlite3_open(":memory:\0".as_ptr() as *const i8, &mut handle) };
1864 assert_eq!(r, ffi::SQLITE_OK);
1865 let db = unsafe { Connection::from_handle_owned(handle) }?;
1866 db.execute_batch("PRAGMA VACUUM")?;
1867 Ok(())
1868 }
1869
1870 mod query_and_then_tests {
1871
1872 use super::*;
1873
1874 #[derive(Debug)]
1875 enum CustomError {
1876 SomeError,
1877 Sqlite(Error),
1878 }
1879
1880 impl fmt::Display for CustomError {
1881 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1882 match *self {
1883 CustomError::SomeError => write!(f, "my custom error"),
1884 CustomError::Sqlite(ref se) => write!(f, "my custom error: {se}"),
1885 }
1886 }
1887 }
1888
1889 impl StdError for CustomError {
1890 fn description(&self) -> &str {
1891 "my custom error"
1892 }
1893
1894 fn cause(&self) -> Option<&dyn StdError> {
1895 match *self {
1896 CustomError::SomeError => None,
1897 CustomError::Sqlite(ref se) => Some(se),
1898 }
1899 }
1900 }
1901
1902 impl From<Error> for CustomError {
1903 fn from(se: Error) -> CustomError {
1904 CustomError::Sqlite(se)
1905 }
1906 }
1907
1908 type CustomResult<T> = Result<T, CustomError>;
1909
1910 #[test]
1911 fn test_query_and_then() -> Result<()> {
1912 let db = Connection::open_in_memory()?;
1913 let sql = "BEGIN;
1914 CREATE TABLE foo(x INTEGER, y TEXT);
1915 INSERT INTO foo VALUES(4, 'hello');
1916 INSERT INTO foo VALUES(3, ', ');
1917 INSERT INTO foo VALUES(2, 'world');
1918 INSERT INTO foo VALUES(1, '!');
1919 END;";
1920 db.execute_batch(sql)?;
1921
1922 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1923 let results: Result<Vec<String>> =
1924 query.query_and_then([], |row| row.get(1))?.collect();
1925
1926 assert_eq!(results?.concat(), "hello, world!");
1927 Ok(())
1928 }
1929
1930 #[test]
1931 fn test_query_and_then_fails() -> Result<()> {
1932 let db = Connection::open_in_memory()?;
1933 let sql = "BEGIN;
1934 CREATE TABLE foo(x INTEGER, y TEXT);
1935 INSERT INTO foo VALUES(4, 'hello');
1936 INSERT INTO foo VALUES(3, ', ');
1937 INSERT INTO foo VALUES(2, 'world');
1938 INSERT INTO foo VALUES(1, '!');
1939 END;";
1940 db.execute_batch(sql)?;
1941
1942 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1943 let bad_type: Result<Vec<f64>> = query.query_and_then([], |row| row.get(1))?.collect();
1944
1945 match bad_type.unwrap_err() {
1946 Error::InvalidColumnType(..) => (),
1947 err => panic!("Unexpected error {}", err),
1948 }
1949
1950 let bad_idx: Result<Vec<String>> =
1951 query.query_and_then([], |row| row.get(3))?.collect();
1952
1953 match bad_idx.unwrap_err() {
1954 Error::InvalidColumnIndex(_) => (),
1955 err => panic!("Unexpected error {}", err),
1956 }
1957 Ok(())
1958 }
1959
1960 #[test]
1961 fn test_query_and_then_custom_error() -> CustomResult<()> {
1962 let db = Connection::open_in_memory()?;
1963 let sql = "BEGIN;
1964 CREATE TABLE foo(x INTEGER, y TEXT);
1965 INSERT INTO foo VALUES(4, 'hello');
1966 INSERT INTO foo VALUES(3, ', ');
1967 INSERT INTO foo VALUES(2, 'world');
1968 INSERT INTO foo VALUES(1, '!');
1969 END;";
1970 db.execute_batch(sql)?;
1971
1972 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1973 let results: CustomResult<Vec<String>> = query
1974 .query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite))?
1975 .collect();
1976
1977 assert_eq!(results?.concat(), "hello, world!");
1978 Ok(())
1979 }
1980
1981 #[test]
1982 fn test_query_and_then_custom_error_fails() -> Result<()> {
1983 let db = Connection::open_in_memory()?;
1984 let sql = "BEGIN;
1985 CREATE TABLE foo(x INTEGER, y TEXT);
1986 INSERT INTO foo VALUES(4, 'hello');
1987 INSERT INTO foo VALUES(3, ', ');
1988 INSERT INTO foo VALUES(2, 'world');
1989 INSERT INTO foo VALUES(1, '!');
1990 END;";
1991 db.execute_batch(sql)?;
1992
1993 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1994 let bad_type: CustomResult<Vec<f64>> = query
1995 .query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite))?
1996 .collect();
1997
1998 match bad_type.unwrap_err() {
1999 CustomError::Sqlite(Error::InvalidColumnType(..)) => (),
2000 err => panic!("Unexpected error {}", err),
2001 }
2002
2003 let bad_idx: CustomResult<Vec<String>> = query
2004 .query_and_then([], |row| row.get(3).map_err(CustomError::Sqlite))?
2005 .collect();
2006
2007 match bad_idx.unwrap_err() {
2008 CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
2009 err => panic!("Unexpected error {}", err),
2010 }
2011
2012 let non_sqlite_err: CustomResult<Vec<String>> = query
2013 .query_and_then([], |_| Err(CustomError::SomeError))?
2014 .collect();
2015
2016 match non_sqlite_err.unwrap_err() {
2017 CustomError::SomeError => (),
2018 err => panic!("Unexpected error {}", err),
2019 }
2020 Ok(())
2021 }
2022
2023 #[test]
2024 fn test_query_row_and_then_custom_error() -> CustomResult<()> {
2025 let db = Connection::open_in_memory()?;
2026 let sql = "BEGIN;
2027 CREATE TABLE foo(x INTEGER, y TEXT);
2028 INSERT INTO foo VALUES(4, 'hello');
2029 END;";
2030 db.execute_batch(sql)?;
2031
2032 let query = "SELECT x, y FROM foo ORDER BY x DESC";
2033 let results: CustomResult<String> =
2034 db.query_row_and_then(query, [], |row| row.get(1).map_err(CustomError::Sqlite));
2035
2036 assert_eq!(results?, "hello");
2037 Ok(())
2038 }
2039
2040 #[test]
2041 fn test_query_row_and_then_custom_error_fails() -> Result<()> {
2042 let db = Connection::open_in_memory()?;
2043 let sql = "BEGIN;
2044 CREATE TABLE foo(x INTEGER, y TEXT);
2045 INSERT INTO foo VALUES(4, 'hello');
2046 END;";
2047 db.execute_batch(sql)?;
2048
2049 let query = "SELECT x, y FROM foo ORDER BY x DESC";
2050 let bad_type: CustomResult<f64> =
2051 db.query_row_and_then(query, [], |row| row.get(1).map_err(CustomError::Sqlite));
2052
2053 match bad_type.unwrap_err() {
2054 CustomError::Sqlite(Error::InvalidColumnType(..)) => (),
2055 err => panic!("Unexpected error {}", err),
2056 }
2057
2058 let bad_idx: CustomResult<String> =
2059 db.query_row_and_then(query, [], |row| row.get(3).map_err(CustomError::Sqlite));
2060
2061 match bad_idx.unwrap_err() {
2062 CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
2063 err => panic!("Unexpected error {}", err),
2064 }
2065
2066 let non_sqlite_err: CustomResult<String> =
2067 db.query_row_and_then(query, [], |_| Err(CustomError::SomeError));
2068
2069 match non_sqlite_err.unwrap_err() {
2070 CustomError::SomeError => (),
2071 err => panic!("Unexpected error {}", err),
2072 }
2073 Ok(())
2074 }
2075 }
2076
2077 #[test]
2078 fn test_dynamic() -> Result<()> {
2079 let db = Connection::open_in_memory()?;
2080 let sql = "BEGIN;
2081 CREATE TABLE foo(x INTEGER, y TEXT);
2082 INSERT INTO foo VALUES(4, 'hello');
2083 END;";
2084 db.execute_batch(sql)?;
2085
2086 db.query_row("SELECT * FROM foo", [], |r| {
2087 assert_eq!(2, r.as_ref().column_count());
2088 Ok(())
2089 })
2090 }
2091 #[test]
2092 fn test_dyn_box() -> Result<()> {
2093 let db = Connection::open_in_memory()?;
2094 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
2095 let b: Box<dyn ToSql> = Box::new(5);
2096 db.execute("INSERT INTO foo VALUES(?1)", [b])?;
2097 db.query_row("SELECT x FROM foo", [], |r| {
2098 assert_eq!(5, r.get_unwrap::<_, i32>(0));
2099 Ok(())
2100 })
2101 }
2102
2103 #[test]
2104 fn test_params() -> Result<()> {
2105 let db = Connection::open_in_memory()?;
2106 db.query_row(
2107 "SELECT
2108 ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10,
2109 ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19, ?20,
2110 ?21, ?22, ?23, ?24, ?25, ?26, ?27, ?28, ?29, ?30,
2111 ?31, ?32, ?33, ?34;",
2112 params![
2113 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,
2114 1, 1, 1, 1, 1, 1,
2115 ],
2116 |r| {
2117 assert_eq!(1, r.get_unwrap::<_, i32>(0));
2118 Ok(())
2119 },
2120 )
2121 }
2122
2123 #[test]
2124 #[cfg(not(feature = "extra_check"))]
2125 fn test_alter_table() -> Result<()> {
2126 let db = Connection::open_in_memory()?;
2127 db.execute_batch("CREATE TABLE x(t);")?;
2128 db.execute("ALTER TABLE x RENAME TO y;", [])?;
2130 Ok(())
2131 }
2132
2133 #[test]
2134 fn test_batch() -> Result<()> {
2135 let db = Connection::open_in_memory()?;
2136 let sql = r"
2137 CREATE TABLE tbl1 (col);
2138 CREATE TABLE tbl2 (col);
2139 ";
2140 let batch = Batch::new(&db, sql);
2141 for stmt in batch {
2142 let mut stmt = stmt?;
2143 stmt.execute([])?;
2144 }
2145 Ok(())
2146 }
2147
2148 #[test]
2149 #[cfg(feature = "modern_sqlite")]
2150 fn test_returning() -> Result<()> {
2151 let db = Connection::open_in_memory()?;
2152 db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)")?;
2153 let row_id = db.one_column::<i64>("INSERT INTO foo DEFAULT VALUES RETURNING ROWID")?;
2154 assert_eq!(row_id, 1);
2155 Ok(())
2156 }
2157
2158 #[test]
2159 fn test_cache_flush() -> Result<()> {
2160 let db = Connection::open_in_memory()?;
2161 db.cache_flush()
2162 }
2163
2164 #[test]
2165 pub fn db_readonly() -> Result<()> {
2166 let db = Connection::open_in_memory()?;
2167 assert!(!db.is_readonly(MAIN_DB)?);
2168 Ok(())
2169 }
2170}