1#![warn(missing_docs)]
55#![cfg_attr(docsrs, feature(doc_cfg))]
56
57pub use libsqlite3_sys as ffi;
58
59use std::cell::RefCell;
60use std::default::Default;
61use std::ffi::{CStr, CString};
62use std::fmt;
63use std::os::raw::{c_char, c_int};
64
65use std::path::{Path, PathBuf};
66use std::result;
67use std::str;
68use std::sync::atomic::Ordering;
69use std::sync::{Arc, Mutex};
70
71use crate::cache::StatementCache;
72use crate::inner_connection::{InnerConnection, BYPASS_SQLITE_INIT};
73use crate::raw_statement::RawStatement;
74use crate::types::ValueRef;
75
76pub use crate::cache::CachedStatement;
77pub use crate::column::Column;
78pub use crate::error::Error;
79pub use crate::ffi::ErrorCode;
80#[cfg(feature = "load_extension")]
81pub use crate::load_extension_guard::LoadExtensionGuard;
82pub use crate::params::{params_from_iter, Params, ParamsFromIter};
83pub use crate::row::{AndThenRows, Map, MappedRows, Row, RowIndex, Rows};
84pub use crate::statement::{Statement, StatementStatus};
85pub use crate::transaction::{DropBehavior, Savepoint, Transaction, TransactionBehavior};
86pub use crate::types::ToSql;
87pub use crate::version::*;
88
89mod error;
90
91#[cfg(feature = "backup")]
92#[cfg_attr(docsrs, doc(cfg(feature = "backup")))]
93pub mod backup;
94#[cfg(feature = "blob")]
95#[cfg_attr(docsrs, doc(cfg(feature = "blob")))]
96pub mod blob;
97mod busy;
98mod cache;
99#[cfg(feature = "collation")]
100#[cfg_attr(docsrs, doc(cfg(feature = "collation")))]
101mod collation;
102mod column;
103pub mod config;
104#[cfg(any(feature = "functions", feature = "vtab"))]
105mod context;
106#[cfg(feature = "functions")]
107#[cfg_attr(docsrs, doc(cfg(feature = "functions")))]
108pub mod functions;
109#[cfg(feature = "hooks")]
110#[cfg_attr(docsrs, doc(cfg(feature = "hooks")))]
111pub mod hooks;
112mod inner_connection;
113#[cfg(feature = "limits")]
114#[cfg_attr(docsrs, doc(cfg(feature = "limits")))]
115pub mod limits;
116#[cfg(feature = "load_extension")]
117mod load_extension_guard;
118mod params;
119mod pragma;
120mod raw_statement;
121mod row;
122#[cfg(feature = "session")]
123#[cfg_attr(docsrs, doc(cfg(feature = "session")))]
124pub mod session;
125mod statement;
126#[cfg(feature = "trace")]
127#[cfg_attr(docsrs, doc(cfg(feature = "trace")))]
128pub mod trace;
129mod transaction;
130pub mod types;
131#[cfg(feature = "unlock_notify")]
132mod unlock_notify;
133mod version;
134#[cfg(feature = "vtab")]
135#[cfg_attr(docsrs, doc(cfg(feature = "vtab")))]
136pub mod vtab;
137
138pub(crate) mod util;
139pub(crate) use util::SmallCString;
140
141const STATEMENT_CACHE_DEFAULT_CAPACITY: usize = 16;
143#[deprecated = "Use an empty array instead; `stmt.execute(NO_PARAMS)` => `stmt.execute([])`"]
149pub const NO_PARAMS: &[&dyn ToSql] = &[];
150
151#[macro_export]
174macro_rules! params {
175 () => {
176 &[] as &[&dyn $crate::ToSql]
177 };
178 ($($param:expr),+ $(,)?) => {
179 &[$(&$param as &dyn $crate::ToSql),+] as &[&dyn $crate::ToSql]
180 };
181}
182
183#[macro_export]
211macro_rules! named_params {
212 () => {
213 &[] as &[(&str, &dyn $crate::ToSql)]
214 };
215 ($($param_name:literal: $param_val:expr),+ $(,)?) => {
218 &[$(($param_name, &$param_val as &dyn $crate::ToSql)),+] as &[(&str, &dyn $crate::ToSql)]
219 };
220}
221
222pub type Result<T, E = Error> = result::Result<T, E>;
224
225pub trait OptionalExtension<T> {
227 fn optional(self) -> Result<Option<T>>;
233}
234
235impl<T> OptionalExtension<T> for Result<T> {
236 fn optional(self) -> Result<Option<T>> {
237 match self {
238 Ok(value) => Ok(Some(value)),
239 Err(Error::QueryReturnedNoRows) => Ok(None),
240 Err(e) => Err(e),
241 }
242 }
243}
244
245unsafe fn errmsg_to_string(errmsg: *const c_char) -> String {
246 let c_slice = CStr::from_ptr(errmsg).to_bytes();
247 String::from_utf8_lossy(c_slice).into_owned()
248}
249
250fn str_to_cstring(s: &str) -> Result<SmallCString> {
251 Ok(SmallCString::new(s)?)
252}
253
254fn str_for_sqlite(s: &[u8]) -> Result<(*const c_char, c_int, ffi::sqlite3_destructor_type)> {
261 let len = len_as_c_int(s.len())?;
262 let (ptr, dtor_info) = if len != 0 {
263 (s.as_ptr().cast::<c_char>(), ffi::SQLITE_TRANSIENT())
264 } else {
265 ("".as_ptr().cast::<c_char>(), ffi::SQLITE_STATIC())
267 };
268 Ok((ptr, len, dtor_info))
269}
270
271fn len_as_c_int(len: usize) -> Result<c_int> {
274 if len >= (c_int::MAX as usize) {
275 Err(Error::SqliteFailure(
276 ffi::Error::new(ffi::SQLITE_TOOBIG),
277 None,
278 ))
279 } else {
280 Ok(len as c_int)
281 }
282}
283
284#[cfg(unix)]
285fn path_to_cstring(p: &Path) -> Result<CString> {
286 use std::os::unix::ffi::OsStrExt;
287 Ok(CString::new(p.as_os_str().as_bytes())?)
288}
289
290#[cfg(not(unix))]
291fn path_to_cstring(p: &Path) -> Result<CString> {
292 let s = p.to_str().ok_or_else(|| Error::InvalidPath(p.to_owned()))?;
293 Ok(CString::new(s)?)
294}
295
296#[derive(Copy, Clone, Debug)]
298pub enum DatabaseName<'a> {
299 Main,
301
302 Temp,
304
305 Attached(&'a str),
307}
308
309pub const MAIN_DB: DatabaseName<'static> = DatabaseName::Main;
311
312pub const TEMP_DB: DatabaseName<'static> = DatabaseName::Temp;
314
315#[cfg(any(
318 feature = "backup",
319 feature = "blob",
320 feature = "session",
321 feature = "modern_sqlite"
322))]
323impl DatabaseName<'_> {
324 #[inline]
325 fn as_cstring(&self) -> Result<SmallCString> {
326 use self::DatabaseName::{Attached, Main, Temp};
327 match *self {
328 Main => str_to_cstring("main"),
329 Temp => str_to_cstring("temp"),
330 Attached(s) => str_to_cstring(s),
331 }
332 }
333}
334
335pub struct Connection {
337 db: RefCell<InnerConnection>,
338 cache: StatementCache,
339 path: Option<PathBuf>,
340}
341
342unsafe impl Send for Connection {}
343
344impl Drop for Connection {
345 #[inline]
346 fn drop(&mut self) {
347 self.flush_prepared_statement_cache();
348 }
349}
350
351impl Connection {
352 #[inline]
405 pub fn open<P: AsRef<Path>>(path: P) -> Result<Connection> {
406 let flags = OpenFlags::default();
407 Connection::open_with_flags(path, flags)
408 }
409
410 #[inline]
416 pub fn open_in_memory() -> Result<Connection> {
417 let flags = OpenFlags::default();
418 Connection::open_in_memory_with_flags(flags)
419 }
420
421 #[inline]
431 pub fn open_with_flags<P: AsRef<Path>>(path: P, flags: OpenFlags) -> Result<Connection> {
432 let c_path = path_to_cstring(path.as_ref())?;
433 InnerConnection::open_with_flags(&c_path, flags, None).map(|db| Connection {
434 db: RefCell::new(db),
435 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
436 path: Some(path.as_ref().to_path_buf()),
437 })
438 }
439
440 #[inline]
451 pub fn open_with_flags_and_vfs<P: AsRef<Path>>(
452 path: P,
453 flags: OpenFlags,
454 vfs: &str,
455 ) -> Result<Connection> {
456 let c_path = path_to_cstring(path.as_ref())?;
457 let c_vfs = str_to_cstring(vfs)?;
458 InnerConnection::open_with_flags(&c_path, flags, Some(&c_vfs)).map(|db| Connection {
459 db: RefCell::new(db),
460 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
461 path: Some(path.as_ref().to_path_buf()),
462 })
463 }
464
465 #[inline]
474 pub fn open_in_memory_with_flags(flags: OpenFlags) -> Result<Connection> {
475 Connection::open_with_flags(":memory:", flags)
476 }
477
478 #[inline]
489 pub fn open_in_memory_with_flags_and_vfs(flags: OpenFlags, vfs: &str) -> Result<Connection> {
490 Connection::open_with_flags_and_vfs(":memory:", flags, vfs)
491 }
492
493 pub fn execute_batch(&self, sql: &str) -> Result<()> {
515 let mut sql = sql;
516 while !sql.is_empty() {
517 let stmt = self.prepare(sql)?;
518 if !stmt.stmt.is_null() && stmt.step()? && cfg!(feature = "extra_check") {
519 return Err(Error::ExecuteReturnedResults);
521 }
522 let tail = stmt.stmt.tail();
523 if tail == 0 || tail >= sql.len() {
524 break;
525 }
526 sql = &sql[tail..];
527 }
528 Ok(())
529 }
530
531 #[inline]
582 pub fn execute<P: Params>(&self, sql: &str, params: P) -> Result<usize> {
583 self.prepare(sql)
584 .and_then(|mut stmt| stmt.check_no_tail().and_then(|_| stmt.execute(params)))
585 }
586
587 #[inline]
593 pub fn path(&self) -> Option<&Path> {
594 self.path.as_deref()
595 }
596
597 #[inline]
602 #[cfg(feature = "release_memory")]
603 pub fn release_memory(&self) -> Result<()> {
604 self.db.borrow_mut().release_memory()
605 }
606
607 #[deprecated = "You can use `execute` with named params now."]
618 pub fn execute_named(&self, sql: &str, params: &[(&str, &dyn ToSql)]) -> Result<usize> {
619 #![allow(deprecated)]
621 self.prepare(sql).and_then(|mut stmt| {
622 stmt.check_no_tail()
623 .and_then(|_| stmt.execute_named(params))
624 })
625 }
626
627 #[inline]
632 pub fn last_insert_rowid(&self) -> i64 {
633 self.db.borrow_mut().last_insert_rowid()
634 }
635
636 #[inline]
664 pub fn query_row<T, P, F>(&self, sql: &str, params: P, f: F) -> Result<T>
665 where
666 P: Params,
667 F: FnOnce(&Row<'_>) -> Result<T>,
668 {
669 let mut stmt = self.prepare(sql)?;
670 stmt.check_no_tail()?;
671 stmt.query_row(params, f)
672 }
673
674 #[deprecated = "You can use `query_row` with named params now."]
689 pub fn query_row_named<T, F>(&self, sql: &str, params: &[(&str, &dyn ToSql)], f: F) -> Result<T>
690 where
691 F: FnOnce(&Row<'_>) -> Result<T>,
692 {
693 self.query_row(sql, params, f)
694 }
695
696 #[inline]
722 pub fn query_row_and_then<T, E, P, F>(&self, sql: &str, params: P, f: F) -> Result<T, E>
723 where
724 P: Params,
725 F: FnOnce(&Row<'_>) -> Result<T, E>,
726 E: From<Error>,
727 {
728 let mut stmt = self.prepare(sql)?;
729 stmt.check_no_tail()?;
730 let mut rows = stmt.query(params)?;
731
732 rows.get_expected_row().map_err(E::from).and_then(f)
733 }
734
735 #[inline]
754 pub fn prepare(&self, sql: &str) -> Result<Statement<'_>> {
755 self.db.borrow_mut().prepare(self, sql)
756 }
757
758 #[inline]
768 pub fn close(self) -> Result<(), (Connection, Error)> {
769 self.flush_prepared_statement_cache();
770 let r = self.db.borrow_mut().close();
771 r.map_err(move |err| (self, err))
772 }
773
774 #[cfg(feature = "load_extension")]
827 #[cfg_attr(docsrs, doc(cfg(feature = "load_extension")))]
828 #[inline]
829 pub unsafe fn load_extension_enable(&self) -> Result<()> {
830 self.db.borrow_mut().enable_load_extension(1)
831 }
832
833 #[cfg(feature = "load_extension")]
841 #[cfg_attr(docsrs, doc(cfg(feature = "load_extension")))]
842 #[inline]
843 pub fn load_extension_disable(&self) -> Result<()> {
844 unsafe { self.db.borrow_mut().enable_load_extension(0) }
846 }
847
848 #[cfg(feature = "load_extension")]
884 #[cfg_attr(docsrs, doc(cfg(feature = "load_extension")))]
885 #[inline]
886 pub unsafe fn load_extension<P: AsRef<Path>>(
887 &self,
888 dylib_path: P,
889 entry_point: Option<&str>,
890 ) -> Result<()> {
891 self.db
892 .borrow_mut()
893 .load_extension(dylib_path.as_ref(), entry_point)
894 }
895
896 #[inline]
910 pub unsafe fn handle(&self) -> *mut ffi::sqlite3 {
911 self.db.borrow().db()
912 }
913
914 #[inline]
923 pub unsafe fn from_handle(db: *mut ffi::sqlite3) -> Result<Connection> {
924 let db_path = db_filename(db);
925 let db = InnerConnection::new(db, false);
926 Ok(Connection {
927 db: RefCell::new(db),
928 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
929 path: db_path,
930 })
931 }
932
933 #[inline]
936 pub fn get_interrupt_handle(&self) -> InterruptHandle {
937 self.db.borrow().get_interrupt_handle()
938 }
939
940 #[inline]
941 fn decode_result(&self, code: c_int) -> Result<()> {
942 self.db.borrow().decode_result(code)
943 }
944
945 #[inline]
951 pub fn changes(&self) -> u64 {
952 self.db.borrow().changes()
953 }
954
955 #[inline]
958 pub fn is_autocommit(&self) -> bool {
959 self.db.borrow().is_autocommit()
960 }
961
962 #[inline]
964 #[cfg(feature = "modern_sqlite")] #[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
966 pub fn is_busy(&self) -> bool {
967 self.db.borrow().is_busy()
968 }
969
970 #[cfg(feature = "modern_sqlite")] #[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
973 pub fn cache_flush(&self) -> Result<()> {
974 self.db.borrow_mut().cache_flush()
975 }
976
977 #[cfg(feature = "modern_sqlite")] #[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
980 pub fn is_readonly(&self, db_name: DatabaseName<'_>) -> Result<bool> {
981 self.db.borrow().db_readonly(db_name)
982 }
983}
984
985impl fmt::Debug for Connection {
986 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
987 f.debug_struct("Connection")
988 .field("path", &self.path)
989 .finish()
990 }
991}
992
993#[derive(Debug)]
1011pub struct Batch<'conn, 'sql> {
1012 conn: &'conn Connection,
1013 sql: &'sql str,
1014 tail: usize,
1015}
1016
1017impl<'conn, 'sql> Batch<'conn, 'sql> {
1018 pub fn new(conn: &'conn Connection, sql: &'sql str) -> Batch<'conn, 'sql> {
1020 Batch { conn, sql, tail: 0 }
1021 }
1022
1023 #[allow(clippy::should_implement_trait)] pub fn next(&mut self) -> Result<Option<Statement<'conn>>> {
1028 while self.tail < self.sql.len() {
1029 let sql = &self.sql[self.tail..];
1030 let next = self.conn.prepare(sql)?;
1031 let tail = next.stmt.tail();
1032 if tail == 0 {
1033 self.tail = self.sql.len();
1034 } else {
1035 self.tail += tail;
1036 }
1037 if next.stmt.is_null() {
1038 continue;
1039 }
1040 return Ok(Some(next));
1041 }
1042 Ok(None)
1043 }
1044}
1045
1046impl<'conn> Iterator for Batch<'conn, '_> {
1047 type Item = Result<Statement<'conn>>;
1048
1049 fn next(&mut self) -> Option<Result<Statement<'conn>>> {
1050 self.next().transpose()
1051 }
1052}
1053
1054bitflags::bitflags! {
1055 #[repr(C)]
1062 pub struct OpenFlags: ::std::os::raw::c_int {
1063 const SQLITE_OPEN_READ_ONLY = ffi::SQLITE_OPEN_READONLY;
1066 const SQLITE_OPEN_READ_WRITE = ffi::SQLITE_OPEN_READWRITE;
1070 const SQLITE_OPEN_CREATE = ffi::SQLITE_OPEN_CREATE;
1072 const SQLITE_OPEN_URI = 0x0000_0040;
1074 const SQLITE_OPEN_MEMORY = 0x0000_0080;
1076 const SQLITE_OPEN_NO_MUTEX = ffi::SQLITE_OPEN_NOMUTEX;
1085 const SQLITE_OPEN_FULL_MUTEX = ffi::SQLITE_OPEN_FULLMUTEX;
1109 const SQLITE_OPEN_SHARED_CACHE = 0x0002_0000;
1116 const SQLITE_OPEN_PRIVATE_CACHE = 0x0004_0000;
1118 const SQLITE_OPEN_NOFOLLOW = 0x0100_0000;
1120 const SQLITE_OPEN_EXRESCODE = 0x0200_0000;
1122 }
1123}
1124
1125impl Default for OpenFlags {
1126 #[inline]
1127 fn default() -> OpenFlags {
1128 OpenFlags::SQLITE_OPEN_READ_WRITE
1131 | OpenFlags::SQLITE_OPEN_CREATE
1132 | OpenFlags::SQLITE_OPEN_NO_MUTEX
1133 | OpenFlags::SQLITE_OPEN_URI
1134 }
1135}
1136
1137pub unsafe fn bypass_sqlite_initialization() {
1157 BYPASS_SQLITE_INIT.store(true, Ordering::Relaxed);
1158}
1159
1160pub struct InterruptHandle {
1162 db_lock: Arc<Mutex<*mut ffi::sqlite3>>,
1163}
1164
1165unsafe impl Send for InterruptHandle {}
1166unsafe impl Sync for InterruptHandle {}
1167
1168impl InterruptHandle {
1169 pub fn interrupt(&self) {
1172 let db_handle = self.db_lock.lock().unwrap();
1173 if !db_handle.is_null() {
1174 unsafe { ffi::sqlite3_interrupt(*db_handle) }
1175 }
1176 }
1177}
1178
1179#[cfg(feature = "modern_sqlite")] unsafe fn db_filename(db: *mut ffi::sqlite3) -> Option<PathBuf> {
1181 let db_name = DatabaseName::Main.as_cstring().unwrap();
1182 let db_filename = ffi::sqlite3_db_filename(db, db_name.as_ptr());
1183 if db_filename.is_null() {
1184 None
1185 } else {
1186 CStr::from_ptr(db_filename).to_str().ok().map(PathBuf::from)
1187 }
1188}
1189#[cfg(not(feature = "modern_sqlite"))]
1190unsafe fn db_filename(_: *mut ffi::sqlite3) -> Option<PathBuf> {
1191 None
1192}
1193
1194#[cfg(doctest)]
1195doc_comment::doctest!("../README.md");
1196
1197#[cfg(test)]
1198mod test {
1199 use super::*;
1200 use crate::ffi;
1201 use fallible_iterator::FallibleIterator;
1202 use std::error::Error as StdError;
1203 use std::fmt;
1204
1205 #[allow(dead_code, unconditional_recursion)]
1209 fn ensure_send<T: Send>() {
1210 ensure_send::<Connection>();
1211 ensure_send::<InterruptHandle>();
1212 }
1213
1214 #[allow(dead_code, unconditional_recursion)]
1215 fn ensure_sync<T: Sync>() {
1216 ensure_sync::<InterruptHandle>();
1217 }
1218
1219 fn checked_memory_handle() -> Connection {
1220 Connection::open_in_memory().unwrap()
1221 }
1222
1223 #[test]
1224 fn test_concurrent_transactions_busy_commit() -> Result<()> {
1225 use std::time::Duration;
1226 let tmp = tempfile::tempdir().unwrap();
1227 let path = tmp.path().join("transactions.db3");
1228
1229 Connection::open(&path)?.execute_batch(
1230 "
1231 BEGIN; CREATE TABLE foo(x INTEGER);
1232 INSERT INTO foo VALUES(42); END;",
1233 )?;
1234
1235 let mut db1 = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_WRITE)?;
1236 let mut db2 = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_ONLY)?;
1237
1238 db1.busy_timeout(Duration::from_millis(0))?;
1239 db2.busy_timeout(Duration::from_millis(0))?;
1240
1241 {
1242 let tx1 = db1.transaction()?;
1243 let tx2 = db2.transaction()?;
1244
1245 tx1.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))?;
1247 tx2.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))?;
1248
1249 tx1.execute("INSERT INTO foo VALUES(?1)", [1])?;
1250 let _ = tx2.execute("INSERT INTO foo VALUES(?1)", [2]);
1251
1252 let _ = tx1.commit();
1253 let _ = tx2.commit();
1254 }
1255
1256 let _ = db1
1257 .transaction()
1258 .expect("commit should have closed transaction");
1259 let _ = db2
1260 .transaction()
1261 .expect("commit should have closed transaction");
1262 Ok(())
1263 }
1264
1265 #[test]
1266 fn test_persistence() -> Result<()> {
1267 let temp_dir = tempfile::tempdir().unwrap();
1268 let path = temp_dir.path().join("test.db3");
1269
1270 {
1271 let db = Connection::open(&path)?;
1272 let sql = "BEGIN;
1273 CREATE TABLE foo(x INTEGER);
1274 INSERT INTO foo VALUES(42);
1275 END;";
1276 db.execute_batch(sql)?;
1277 }
1278
1279 let path_string = path.to_str().unwrap();
1280 let db = Connection::open(&path_string)?;
1281 let the_answer: Result<i64> = db.query_row("SELECT x FROM foo", [], |r| r.get(0));
1282
1283 assert_eq!(42i64, the_answer?);
1284 Ok(())
1285 }
1286
1287 #[test]
1288 fn test_open() {
1289 assert!(Connection::open_in_memory().is_ok());
1290
1291 let db = checked_memory_handle();
1292 assert!(db.close().is_ok());
1293 }
1294
1295 #[test]
1296 fn test_open_failure() {
1297 let filename = "no_such_file.db";
1298 let result = Connection::open_with_flags(filename, OpenFlags::SQLITE_OPEN_READ_ONLY);
1299 assert!(result.is_err());
1300 let err = result.unwrap_err();
1301 if let Error::SqliteFailure(e, Some(msg)) = err {
1302 assert_eq!(ErrorCode::CannotOpen, e.code);
1303 assert_eq!(ffi::SQLITE_CANTOPEN, e.extended_code);
1304 assert!(
1305 msg.contains(filename),
1306 "error message '{}' does not contain '{}'",
1307 msg,
1308 filename
1309 );
1310 } else {
1311 panic!("SqliteFailure expected");
1312 }
1313 }
1314
1315 #[cfg(unix)]
1316 #[test]
1317 fn test_invalid_unicode_file_names() -> Result<()> {
1318 use std::ffi::OsStr;
1319 use std::fs::File;
1320 use std::os::unix::ffi::OsStrExt;
1321 let temp_dir = tempfile::tempdir().unwrap();
1322
1323 let path = temp_dir.path();
1324 if File::create(path.join(OsStr::from_bytes(&[0xFE]))).is_err() {
1325 return Ok(());
1327 }
1328 let db_path = path.join(OsStr::from_bytes(&[0xFF]));
1329 {
1330 let db = Connection::open(&db_path)?;
1331 let sql = "BEGIN;
1332 CREATE TABLE foo(x INTEGER);
1333 INSERT INTO foo VALUES(42);
1334 END;";
1335 db.execute_batch(sql)?;
1336 }
1337
1338 let db = Connection::open(&db_path)?;
1339 let the_answer: Result<i64> = db.query_row("SELECT x FROM foo", [], |r| r.get(0));
1340
1341 assert_eq!(42i64, the_answer?);
1342 Ok(())
1343 }
1344
1345 #[test]
1346 fn test_close_retry() -> Result<()> {
1347 let db = Connection::open_in_memory()?;
1348
1349 let raw_stmt = {
1353 use super::str_to_cstring;
1354 use std::os::raw::c_int;
1355 use std::ptr;
1356
1357 let raw_db = db.db.borrow_mut().db;
1358 let sql = "SELECT 1";
1359 let mut raw_stmt: *mut ffi::sqlite3_stmt = ptr::null_mut();
1360 let cstring = str_to_cstring(sql)?;
1361 let rc = unsafe {
1362 ffi::sqlite3_prepare_v2(
1363 raw_db,
1364 cstring.as_ptr(),
1365 (sql.len() + 1) as c_int,
1366 &mut raw_stmt,
1367 ptr::null_mut(),
1368 )
1369 };
1370 assert_eq!(rc, ffi::SQLITE_OK);
1371 raw_stmt
1372 };
1373
1374 let (db, _) = db.close().unwrap_err();
1377 let (db, _) = db.close().unwrap_err();
1378 let (db, _) = db.close().unwrap_err();
1379
1380 assert_eq!(ffi::SQLITE_OK, unsafe { ffi::sqlite3_finalize(raw_stmt) });
1382
1383 db.close().unwrap();
1384 Ok(())
1385 }
1386
1387 #[test]
1388 fn test_open_with_flags() {
1389 for bad_flags in &[
1390 OpenFlags::empty(),
1391 OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_READ_WRITE,
1392 OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_CREATE,
1393 ] {
1394 assert!(Connection::open_in_memory_with_flags(*bad_flags).is_err());
1395 }
1396 }
1397
1398 #[test]
1399 fn test_execute_batch() -> Result<()> {
1400 let db = Connection::open_in_memory()?;
1401 let sql = "BEGIN;
1402 CREATE TABLE foo(x INTEGER);
1403 INSERT INTO foo VALUES(1);
1404 INSERT INTO foo VALUES(2);
1405 INSERT INTO foo VALUES(3);
1406 INSERT INTO foo VALUES(4);
1407 END;";
1408 db.execute_batch(sql)?;
1409
1410 db.execute_batch("UPDATE foo SET x = 3 WHERE x < 3")?;
1411
1412 assert!(db.execute_batch("INVALID SQL").is_err());
1413 Ok(())
1414 }
1415
1416 #[test]
1417 fn test_execute() -> Result<()> {
1418 let db = Connection::open_in_memory()?;
1419 db.execute_batch("CREATE TABLE foo(x INTEGER)")?;
1420
1421 assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?)", [1i32])?);
1422 assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?)", [2i32])?);
1423
1424 assert_eq!(
1425 3i32,
1426 db.query_row::<i32, _, _>("SELECT SUM(x) FROM foo", [], |r| r.get(0))?
1427 );
1428 Ok(())
1429 }
1430
1431 #[test]
1432 #[cfg(feature = "extra_check")]
1433 fn test_execute_select() {
1434 let db = checked_memory_handle();
1435 let err = db.execute("SELECT 1 WHERE 1 < ?", [1i32]).unwrap_err();
1436 assert_eq!(
1437 err,
1438 Error::ExecuteReturnedResults,
1439 "Unexpected error: {}",
1440 err
1441 );
1442 }
1443
1444 #[test]
1445 #[cfg(feature = "extra_check")]
1446 fn test_execute_multiple() {
1447 let db = checked_memory_handle();
1448 let err = db
1449 .execute(
1450 "CREATE TABLE foo(x INTEGER); CREATE TABLE foo(x INTEGER)",
1451 [],
1452 )
1453 .unwrap_err();
1454 match err {
1455 Error::MultipleStatement => (),
1456 _ => panic!("Unexpected error: {}", err),
1457 }
1458 }
1459
1460 #[test]
1461 fn test_prepare_column_names() -> Result<()> {
1462 let db = Connection::open_in_memory()?;
1463 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1464
1465 let stmt = db.prepare("SELECT * FROM foo")?;
1466 assert_eq!(stmt.column_count(), 1);
1467 assert_eq!(stmt.column_names(), vec!["x"]);
1468
1469 let stmt = db.prepare("SELECT x AS a, x AS b FROM foo")?;
1470 assert_eq!(stmt.column_count(), 2);
1471 assert_eq!(stmt.column_names(), vec!["a", "b"]);
1472 Ok(())
1473 }
1474
1475 #[test]
1476 fn test_prepare_execute() -> Result<()> {
1477 let db = Connection::open_in_memory()?;
1478 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1479
1480 let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?)")?;
1481 assert_eq!(insert_stmt.execute([1i32])?, 1);
1482 assert_eq!(insert_stmt.execute([2i32])?, 1);
1483 assert_eq!(insert_stmt.execute([3i32])?, 1);
1484
1485 assert_eq!(insert_stmt.execute(["hello"])?, 1);
1486 assert_eq!(insert_stmt.execute(["goodbye"])?, 1);
1487 assert_eq!(insert_stmt.execute([types::Null])?, 1);
1488
1489 let mut update_stmt = db.prepare("UPDATE foo SET x=? WHERE x<?")?;
1490 assert_eq!(update_stmt.execute([3i32, 3i32])?, 2);
1491 assert_eq!(update_stmt.execute([3i32, 3i32])?, 0);
1492 assert_eq!(update_stmt.execute([8i32, 8i32])?, 3);
1493 Ok(())
1494 }
1495
1496 #[test]
1497 fn test_prepare_query() -> Result<()> {
1498 let db = Connection::open_in_memory()?;
1499 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1500
1501 let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?)")?;
1502 assert_eq!(insert_stmt.execute([1i32])?, 1);
1503 assert_eq!(insert_stmt.execute([2i32])?, 1);
1504 assert_eq!(insert_stmt.execute([3i32])?, 1);
1505
1506 let mut query = db.prepare("SELECT x FROM foo WHERE x < ? ORDER BY x DESC")?;
1507 {
1508 let mut rows = query.query([4i32])?;
1509 let mut v = Vec::<i32>::new();
1510
1511 while let Some(row) = rows.next()? {
1512 v.push(row.get(0)?);
1513 }
1514
1515 assert_eq!(v, [3i32, 2, 1]);
1516 }
1517
1518 {
1519 let mut rows = query.query([3i32])?;
1520 let mut v = Vec::<i32>::new();
1521
1522 while let Some(row) = rows.next()? {
1523 v.push(row.get(0)?);
1524 }
1525
1526 assert_eq!(v, [2i32, 1]);
1527 }
1528 Ok(())
1529 }
1530
1531 #[test]
1532 fn test_query_map() -> Result<()> {
1533 let db = Connection::open_in_memory()?;
1534 let sql = "BEGIN;
1535 CREATE TABLE foo(x INTEGER, y TEXT);
1536 INSERT INTO foo VALUES(4, \"hello\");
1537 INSERT INTO foo VALUES(3, \", \");
1538 INSERT INTO foo VALUES(2, \"world\");
1539 INSERT INTO foo VALUES(1, \"!\");
1540 END;";
1541 db.execute_batch(sql)?;
1542
1543 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1544 let results: Result<Vec<String>> = query.query([])?.map(|row| row.get(1)).collect();
1545
1546 assert_eq!(results?.concat(), "hello, world!");
1547 Ok(())
1548 }
1549
1550 #[test]
1551 fn test_query_row() -> Result<()> {
1552 let db = Connection::open_in_memory()?;
1553 let sql = "BEGIN;
1554 CREATE TABLE foo(x INTEGER);
1555 INSERT INTO foo VALUES(1);
1556 INSERT INTO foo VALUES(2);
1557 INSERT INTO foo VALUES(3);
1558 INSERT INTO foo VALUES(4);
1559 END;";
1560 db.execute_batch(sql)?;
1561
1562 assert_eq!(
1563 10i64,
1564 db.query_row::<i64, _, _>("SELECT SUM(x) FROM foo", [], |r| r.get(0))?
1565 );
1566
1567 let result: Result<i64> = db.query_row("SELECT x FROM foo WHERE x > 5", [], |r| r.get(0));
1568 match result.unwrap_err() {
1569 Error::QueryReturnedNoRows => (),
1570 err => panic!("Unexpected error {}", err),
1571 }
1572
1573 let bad_query_result = db.query_row("NOT A PROPER QUERY; test123", [], |_| Ok(()));
1574
1575 assert!(bad_query_result.is_err());
1576 Ok(())
1577 }
1578
1579 #[test]
1580 fn test_optional() -> Result<()> {
1581 let db = Connection::open_in_memory()?;
1582
1583 let result: Result<i64> = db.query_row("SELECT 1 WHERE 0 <> 0", [], |r| r.get(0));
1584 let result = result.optional();
1585 match result? {
1586 None => (),
1587 _ => panic!("Unexpected result"),
1588 }
1589
1590 let result: Result<i64> = db.query_row("SELECT 1 WHERE 0 == 0", [], |r| r.get(0));
1591 let result = result.optional();
1592 match result? {
1593 Some(1) => (),
1594 _ => panic!("Unexpected result"),
1595 }
1596
1597 let bad_query_result: Result<i64> = db.query_row("NOT A PROPER QUERY", [], |r| r.get(0));
1598 let bad_query_result = bad_query_result.optional();
1599 assert!(bad_query_result.is_err());
1600 Ok(())
1601 }
1602
1603 #[test]
1604 fn test_pragma_query_row() -> Result<()> {
1605 let db = Connection::open_in_memory()?;
1606 assert_eq!(
1607 "memory",
1608 db.query_row::<String, _, _>("PRAGMA journal_mode", [], |r| r.get(0))?
1609 );
1610 let mode = db.query_row::<String, _, _>("PRAGMA journal_mode=off", [], |r| r.get(0))?;
1611 if cfg!(features = "bundled") {
1612 assert_eq!(mode, "off");
1613 } else {
1614 assert!(mode == "memory" || mode == "off", "Got mode {:?}", mode);
1626 }
1627
1628 Ok(())
1629 }
1630
1631 #[test]
1632 fn test_prepare_failures() -> Result<()> {
1633 let db = Connection::open_in_memory()?;
1634 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1635
1636 let err = db.prepare("SELECT * FROM does_not_exist").unwrap_err();
1637 assert!(format!("{}", err).contains("does_not_exist"));
1638 Ok(())
1639 }
1640
1641 #[test]
1642 fn test_last_insert_rowid() -> Result<()> {
1643 let db = Connection::open_in_memory()?;
1644 db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)")?;
1645 db.execute_batch("INSERT INTO foo DEFAULT VALUES")?;
1646
1647 assert_eq!(db.last_insert_rowid(), 1);
1648
1649 let mut stmt = db.prepare("INSERT INTO foo DEFAULT VALUES")?;
1650 for _ in 0i32..9 {
1651 stmt.execute([])?;
1652 }
1653 assert_eq!(db.last_insert_rowid(), 10);
1654 Ok(())
1655 }
1656
1657 #[test]
1658 fn test_is_autocommit() -> Result<()> {
1659 let db = Connection::open_in_memory()?;
1660 assert!(
1661 db.is_autocommit(),
1662 "autocommit expected to be active by default"
1663 );
1664 Ok(())
1665 }
1666
1667 #[test]
1668 #[cfg(feature = "modern_sqlite")]
1669 fn test_is_busy() -> Result<()> {
1670 let db = Connection::open_in_memory()?;
1671 assert!(!db.is_busy());
1672 let mut stmt = db.prepare("PRAGMA schema_version")?;
1673 assert!(!db.is_busy());
1674 {
1675 let mut rows = stmt.query([])?;
1676 assert!(!db.is_busy());
1677 let row = rows.next()?;
1678 assert!(db.is_busy());
1679 assert!(row.is_some());
1680 }
1681 assert!(!db.is_busy());
1682 Ok(())
1683 }
1684
1685 #[test]
1686 fn test_statement_debugging() -> Result<()> {
1687 let db = Connection::open_in_memory()?;
1688 let query = "SELECT 12345";
1689 let stmt = db.prepare(query)?;
1690
1691 assert!(format!("{:?}", stmt).contains(query));
1692 Ok(())
1693 }
1694
1695 #[test]
1696 fn test_notnull_constraint_error() -> Result<()> {
1697 #[cfg(feature = "modern_sqlite")]
1700 fn check_extended_code(extended_code: c_int) {
1701 assert_eq!(extended_code, ffi::SQLITE_CONSTRAINT_NOTNULL);
1702 }
1703 #[cfg(not(feature = "modern_sqlite"))]
1704 fn check_extended_code(_extended_code: c_int) {}
1705
1706 let db = Connection::open_in_memory()?;
1707 db.execute_batch("CREATE TABLE foo(x NOT NULL)")?;
1708
1709 let result = db.execute("INSERT INTO foo (x) VALUES (NULL)", []);
1710 assert!(result.is_err());
1711
1712 match result.unwrap_err() {
1713 Error::SqliteFailure(err, _) => {
1714 assert_eq!(err.code, ErrorCode::ConstraintViolation);
1715 check_extended_code(err.extended_code);
1716 }
1717 err => panic!("Unexpected error {}", err),
1718 }
1719 Ok(())
1720 }
1721
1722 #[test]
1723 fn test_version_string() {
1724 let n = version_number();
1725 let major = n / 1_000_000;
1726 let minor = (n % 1_000_000) / 1_000;
1727 let patch = n % 1_000;
1728
1729 assert!(version().contains(&format!("{}.{}.{}", major, minor, patch)));
1730 }
1731
1732 #[test]
1733 #[cfg(feature = "functions")]
1734 fn test_interrupt() -> Result<()> {
1735 let db = Connection::open_in_memory()?;
1736
1737 let interrupt_handle = db.get_interrupt_handle();
1738
1739 db.create_scalar_function(
1740 "interrupt",
1741 0,
1742 functions::FunctionFlags::default(),
1743 move |_| {
1744 interrupt_handle.interrupt();
1745 Ok(0)
1746 },
1747 )?;
1748
1749 let mut stmt =
1750 db.prepare("SELECT interrupt() FROM (SELECT 1 UNION SELECT 2 UNION SELECT 3)")?;
1751
1752 let result: Result<Vec<i32>> = stmt.query([])?.map(|r| r.get(0)).collect();
1753
1754 assert_eq!(
1755 result.unwrap_err().sqlite_error_code(),
1756 Some(ErrorCode::OperationInterrupted)
1757 );
1758 Ok(())
1759 }
1760
1761 #[test]
1762 fn test_interrupt_close() {
1763 let db = checked_memory_handle();
1764 let handle = db.get_interrupt_handle();
1765 handle.interrupt();
1766 db.close().unwrap();
1767 handle.interrupt();
1768
1769 let db_guard = handle.db_lock.lock().unwrap();
1771 assert!(db_guard.is_null());
1772 }
1776
1777 #[test]
1778 fn test_get_raw() -> Result<()> {
1779 let db = Connection::open_in_memory()?;
1780 db.execute_batch("CREATE TABLE foo(i, x);")?;
1781 let vals = ["foobar", "1234", "qwerty"];
1782 let mut insert_stmt = db.prepare("INSERT INTO foo(i, x) VALUES(?, ?)")?;
1783 for (i, v) in vals.iter().enumerate() {
1784 let i_to_insert = i as i64;
1785 assert_eq!(insert_stmt.execute(params![i_to_insert, v])?, 1);
1786 }
1787
1788 let mut query = db.prepare("SELECT i, x FROM foo")?;
1789 let mut rows = query.query([])?;
1790
1791 while let Some(row) = rows.next()? {
1792 let i = row.get_ref(0)?.as_i64()?;
1793 let expect = vals[i as usize];
1794 let x = row.get_ref("x")?.as_str()?;
1795 assert_eq!(x, expect);
1796 }
1797
1798 let mut query = db.prepare("SELECT x FROM foo")?;
1799 let rows = query.query_map([], |row| {
1800 let x = row.get_ref(0)?.as_str()?; Ok(x[..].to_owned())
1802 })?;
1803
1804 for (i, row) in rows.enumerate() {
1805 assert_eq!(row?, vals[i]);
1806 }
1807 Ok(())
1808 }
1809
1810 #[test]
1811 fn test_from_handle() -> Result<()> {
1812 let db = Connection::open_in_memory()?;
1813 let handle = unsafe { db.handle() };
1814 {
1815 let db = unsafe { Connection::from_handle(handle) }?;
1816 db.execute_batch("PRAGMA VACUUM")?;
1817 }
1818 db.close().unwrap();
1819 Ok(())
1820 }
1821
1822 mod query_and_then_tests {
1823
1824 use super::*;
1825
1826 #[derive(Debug)]
1827 enum CustomError {
1828 SomeError,
1829 Sqlite(Error),
1830 }
1831
1832 impl fmt::Display for CustomError {
1833 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1834 match *self {
1835 CustomError::SomeError => write!(f, "my custom error"),
1836 CustomError::Sqlite(ref se) => write!(f, "my custom error: {}", se),
1837 }
1838 }
1839 }
1840
1841 impl StdError for CustomError {
1842 fn description(&self) -> &str {
1843 "my custom error"
1844 }
1845
1846 fn cause(&self) -> Option<&dyn StdError> {
1847 match *self {
1848 CustomError::SomeError => None,
1849 CustomError::Sqlite(ref se) => Some(se),
1850 }
1851 }
1852 }
1853
1854 impl From<Error> for CustomError {
1855 fn from(se: Error) -> CustomError {
1856 CustomError::Sqlite(se)
1857 }
1858 }
1859
1860 type CustomResult<T> = Result<T, CustomError>;
1861
1862 #[test]
1863 fn test_query_and_then() -> Result<()> {
1864 let db = Connection::open_in_memory()?;
1865 let sql = "BEGIN;
1866 CREATE TABLE foo(x INTEGER, y TEXT);
1867 INSERT INTO foo VALUES(4, \"hello\");
1868 INSERT INTO foo VALUES(3, \", \");
1869 INSERT INTO foo VALUES(2, \"world\");
1870 INSERT INTO foo VALUES(1, \"!\");
1871 END;";
1872 db.execute_batch(sql)?;
1873
1874 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1875 let results: Result<Vec<String>> =
1876 query.query_and_then([], |row| row.get(1))?.collect();
1877
1878 assert_eq!(results?.concat(), "hello, world!");
1879 Ok(())
1880 }
1881
1882 #[test]
1883 fn test_query_and_then_fails() -> Result<()> {
1884 let db = Connection::open_in_memory()?;
1885 let sql = "BEGIN;
1886 CREATE TABLE foo(x INTEGER, y TEXT);
1887 INSERT INTO foo VALUES(4, \"hello\");
1888 INSERT INTO foo VALUES(3, \", \");
1889 INSERT INTO foo VALUES(2, \"world\");
1890 INSERT INTO foo VALUES(1, \"!\");
1891 END;";
1892 db.execute_batch(sql)?;
1893
1894 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1895 let bad_type: Result<Vec<f64>> = query.query_and_then([], |row| row.get(1))?.collect();
1896
1897 match bad_type.unwrap_err() {
1898 Error::InvalidColumnType(..) => (),
1899 err => panic!("Unexpected error {}", err),
1900 }
1901
1902 let bad_idx: Result<Vec<String>> =
1903 query.query_and_then([], |row| row.get(3))?.collect();
1904
1905 match bad_idx.unwrap_err() {
1906 Error::InvalidColumnIndex(_) => (),
1907 err => panic!("Unexpected error {}", err),
1908 }
1909 Ok(())
1910 }
1911
1912 #[test]
1913 fn test_query_and_then_custom_error() -> CustomResult<()> {
1914 let db = Connection::open_in_memory()?;
1915 let sql = "BEGIN;
1916 CREATE TABLE foo(x INTEGER, y TEXT);
1917 INSERT INTO foo VALUES(4, \"hello\");
1918 INSERT INTO foo VALUES(3, \", \");
1919 INSERT INTO foo VALUES(2, \"world\");
1920 INSERT INTO foo VALUES(1, \"!\");
1921 END;";
1922 db.execute_batch(sql)?;
1923
1924 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1925 let results: CustomResult<Vec<String>> = query
1926 .query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite))?
1927 .collect();
1928
1929 assert_eq!(results?.concat(), "hello, world!");
1930 Ok(())
1931 }
1932
1933 #[test]
1934 fn test_query_and_then_custom_error_fails() -> Result<()> {
1935 let db = Connection::open_in_memory()?;
1936 let sql = "BEGIN;
1937 CREATE TABLE foo(x INTEGER, y TEXT);
1938 INSERT INTO foo VALUES(4, \"hello\");
1939 INSERT INTO foo VALUES(3, \", \");
1940 INSERT INTO foo VALUES(2, \"world\");
1941 INSERT INTO foo VALUES(1, \"!\");
1942 END;";
1943 db.execute_batch(sql)?;
1944
1945 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1946 let bad_type: CustomResult<Vec<f64>> = query
1947 .query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite))?
1948 .collect();
1949
1950 match bad_type.unwrap_err() {
1951 CustomError::Sqlite(Error::InvalidColumnType(..)) => (),
1952 err => panic!("Unexpected error {}", err),
1953 }
1954
1955 let bad_idx: CustomResult<Vec<String>> = query
1956 .query_and_then([], |row| row.get(3).map_err(CustomError::Sqlite))?
1957 .collect();
1958
1959 match bad_idx.unwrap_err() {
1960 CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
1961 err => panic!("Unexpected error {}", err),
1962 }
1963
1964 let non_sqlite_err: CustomResult<Vec<String>> = query
1965 .query_and_then([], |_| Err(CustomError::SomeError))?
1966 .collect();
1967
1968 match non_sqlite_err.unwrap_err() {
1969 CustomError::SomeError => (),
1970 err => panic!("Unexpected error {}", err),
1971 }
1972 Ok(())
1973 }
1974
1975 #[test]
1976 fn test_query_row_and_then_custom_error() -> CustomResult<()> {
1977 let db = Connection::open_in_memory()?;
1978 let sql = "BEGIN;
1979 CREATE TABLE foo(x INTEGER, y TEXT);
1980 INSERT INTO foo VALUES(4, \"hello\");
1981 END;";
1982 db.execute_batch(sql)?;
1983
1984 let query = "SELECT x, y FROM foo ORDER BY x DESC";
1985 let results: CustomResult<String> =
1986 db.query_row_and_then(query, [], |row| row.get(1).map_err(CustomError::Sqlite));
1987
1988 assert_eq!(results?, "hello");
1989 Ok(())
1990 }
1991
1992 #[test]
1993 fn test_query_row_and_then_custom_error_fails() -> Result<()> {
1994 let db = Connection::open_in_memory()?;
1995 let sql = "BEGIN;
1996 CREATE TABLE foo(x INTEGER, y TEXT);
1997 INSERT INTO foo VALUES(4, \"hello\");
1998 END;";
1999 db.execute_batch(sql)?;
2000
2001 let query = "SELECT x, y FROM foo ORDER BY x DESC";
2002 let bad_type: CustomResult<f64> =
2003 db.query_row_and_then(query, [], |row| row.get(1).map_err(CustomError::Sqlite));
2004
2005 match bad_type.unwrap_err() {
2006 CustomError::Sqlite(Error::InvalidColumnType(..)) => (),
2007 err => panic!("Unexpected error {}", err),
2008 }
2009
2010 let bad_idx: CustomResult<String> =
2011 db.query_row_and_then(query, [], |row| row.get(3).map_err(CustomError::Sqlite));
2012
2013 match bad_idx.unwrap_err() {
2014 CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
2015 err => panic!("Unexpected error {}", err),
2016 }
2017
2018 let non_sqlite_err: CustomResult<String> =
2019 db.query_row_and_then(query, [], |_| Err(CustomError::SomeError));
2020
2021 match non_sqlite_err.unwrap_err() {
2022 CustomError::SomeError => (),
2023 err => panic!("Unexpected error {}", err),
2024 }
2025 Ok(())
2026 }
2027 }
2028
2029 #[test]
2030 fn test_dynamic() -> Result<()> {
2031 let db = Connection::open_in_memory()?;
2032 let sql = "BEGIN;
2033 CREATE TABLE foo(x INTEGER, y TEXT);
2034 INSERT INTO foo VALUES(4, \"hello\");
2035 END;";
2036 db.execute_batch(sql)?;
2037
2038 db.query_row("SELECT * FROM foo", [], |r| {
2039 assert_eq!(2, r.as_ref().column_count());
2040 Ok(())
2041 })
2042 }
2043 #[test]
2044 fn test_dyn_box() -> Result<()> {
2045 let db = Connection::open_in_memory()?;
2046 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
2047 let b: Box<dyn ToSql> = Box::new(5);
2048 db.execute("INSERT INTO foo VALUES(?)", [b])?;
2049 db.query_row("SELECT x FROM foo", [], |r| {
2050 assert_eq!(5, r.get_unwrap::<_, i32>(0));
2051 Ok(())
2052 })
2053 }
2054
2055 #[test]
2056 fn test_params() -> Result<()> {
2057 let db = Connection::open_in_memory()?;
2058 db.query_row(
2059 "SELECT
2060 ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
2061 ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
2062 ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
2063 ?, ?, ?, ?;",
2064 params![
2065 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,
2066 1, 1, 1, 1, 1, 1,
2067 ],
2068 |r| {
2069 assert_eq!(1, r.get_unwrap::<_, i32>(0));
2070 Ok(())
2071 },
2072 )
2073 }
2074
2075 #[test]
2076 #[cfg(not(feature = "extra_check"))]
2077 fn test_alter_table() -> Result<()> {
2078 let db = Connection::open_in_memory()?;
2079 db.execute_batch("CREATE TABLE x(t);")?;
2080 db.execute("ALTER TABLE x RENAME TO y;", [])?;
2082 Ok(())
2083 }
2084
2085 #[test]
2086 fn test_batch() -> Result<()> {
2087 let db = Connection::open_in_memory()?;
2088 let sql = r"
2089 CREATE TABLE tbl1 (col);
2090 CREATE TABLE tbl2 (col);
2091 ";
2092 let batch = Batch::new(&db, sql);
2093 for stmt in batch {
2094 let mut stmt = stmt?;
2095 stmt.execute([])?;
2096 }
2097 Ok(())
2098 }
2099
2100 #[test]
2101 #[cfg(feature = "modern_sqlite")]
2102 fn test_returning() -> Result<()> {
2103 let db = Connection::open_in_memory()?;
2104 db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)")?;
2105 let row_id =
2106 db.query_row::<i64, _, _>("INSERT INTO foo DEFAULT VALUES RETURNING ROWID", [], |r| {
2107 r.get(0)
2108 })?;
2109 assert_eq!(row_id, 1);
2110 Ok(())
2111 }
2112
2113 #[test]
2114 #[cfg(feature = "modern_sqlite")]
2115 fn test_cache_flush() -> Result<()> {
2116 let db = Connection::open_in_memory()?;
2117 db.cache_flush()
2118 }
2119
2120 #[test]
2121 #[cfg(feature = "modern_sqlite")]
2122 pub fn db_readonly() -> Result<()> {
2123 let db = Connection::open_in_memory()?;
2124 assert!(!db.is_readonly(MAIN_DB)?);
2125 Ok(())
2126 }
2127}