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}