1#![warn(missing_docs)]
51
52pub use libsqlite3_sys as ffi;
53
54use std::cell::RefCell;
55use std::convert;
56use std::default::Default;
57use std::ffi::{CStr, CString};
58use std::fmt;
59use std::os::raw::{c_char, c_int};
60
61use std::path::{Path, PathBuf};
62use std::result;
63use std::str;
64use std::sync::atomic::Ordering;
65use std::sync::{Arc, Mutex};
66
67use crate::cache::StatementCache;
68use crate::inner_connection::{InnerConnection, BYPASS_SQLITE_INIT};
69use crate::raw_statement::RawStatement;
70use crate::types::ValueRef;
71
72pub use crate::cache::CachedStatement;
73pub use crate::column::Column;
74#[cfg(any(
75 feature = "loadable_extension",
76 feature = "loadable_extension_embedded"
77))]
78pub use crate::error::to_sqlite_error;
79pub use crate::error::Error;
80pub use crate::ffi::ErrorCode;
81#[cfg(feature = "hooks")]
82pub use crate::hooks::Action;
83#[cfg(feature = "load_extension")]
84pub use crate::load_extension_guard::LoadExtensionGuard;
85pub use crate::params::{params_from_iter, Params, ParamsFromIter};
86pub use crate::row::{AndThenRows, Map, MappedRows, Row, RowIndex, Rows};
87pub use crate::statement::{Statement, StatementStatus};
88pub use crate::transaction::{DropBehavior, Savepoint, Transaction, TransactionBehavior};
89pub use crate::types::ToSql;
90pub use crate::version::*;
91
92#[macro_use]
93mod error;
94
95#[cfg(feature = "backup")]
96pub mod backup;
97#[cfg(feature = "blob")]
98pub mod blob;
99mod busy;
100mod cache;
101#[cfg(feature = "collation")]
102mod collation;
103mod column;
104#[cfg(not(any(
105 feature = "loadable_extension",
106 feature = "loadable_extension_embedded"
107)))]
108pub mod config;
109#[cfg(any(feature = "functions", feature = "vtab"))]
110mod context;
111#[cfg(feature = "functions")]
112pub mod functions;
113#[cfg(feature = "hooks")]
114mod hooks;
115mod inner_connection;
116#[cfg(feature = "limits")]
117pub mod limits;
118#[cfg(feature = "load_extension")]
119mod load_extension_guard;
120mod params;
121mod pragma;
122mod raw_statement;
123mod row;
124#[cfg(feature = "session")]
125pub mod session;
126mod statement;
127#[cfg(feature = "trace")]
128pub mod trace;
129mod transaction;
130pub mod types;
131mod unlock_notify;
132mod version;
133#[cfg(feature = "vtab")]
134pub mod vtab;
135
136pub(crate) mod util;
137pub(crate) use util::SmallCString;
138
139const STATEMENT_CACHE_DEFAULT_CAPACITY: usize = 16;
141#[deprecated = "Use an empty array instead; `stmt.execute(NO_PARAMS)` => `stmt.execute([])`"]
147pub const NO_PARAMS: &[&dyn ToSql] = &[];
148
149#[macro_export]
171macro_rules! params {
172 () => {
173 &[] as &[&dyn $crate::ToSql]
174 };
175 ($($param:expr),+ $(,)?) => {
176 &[$(&$param as &dyn $crate::ToSql),+] as &[&dyn $crate::ToSql]
177 };
178}
179
180#[macro_export]
208macro_rules! named_params {
209 () => {
210 &[] as &[(&str, &dyn $crate::ToSql)]
211 };
212 ($($param_name:literal: $param_val:expr),+ $(,)?) => {
215 &[$(($param_name, &$param_val as &dyn $crate::ToSql)),+] as &[(&str, &dyn $crate::ToSql)]
216 };
217}
218
219pub type Result<T, E = Error> = result::Result<T, E>;
221
222pub trait OptionalExtension<T> {
224 fn optional(self) -> Result<Option<T>>;
230}
231
232impl<T> OptionalExtension<T> for Result<T> {
233 fn optional(self) -> Result<Option<T>> {
234 match self {
235 Ok(value) => Ok(Some(value)),
236 Err(Error::QueryReturnedNoRows) => Ok(None),
237 Err(e) => Err(e),
238 }
239 }
240}
241
242unsafe fn errmsg_to_string(errmsg: *const c_char) -> String {
243 let c_slice = CStr::from_ptr(errmsg).to_bytes();
244 String::from_utf8_lossy(c_slice).into_owned()
245}
246
247fn str_to_cstring(s: &str) -> Result<SmallCString> {
248 Ok(SmallCString::new(s)?)
249}
250
251fn str_for_sqlite(s: &[u8]) -> Result<(*const c_char, c_int, ffi::sqlite3_destructor_type)> {
258 let len = len_as_c_int(s.len())?;
259 let (ptr, dtor_info) = if len != 0 {
260 (s.as_ptr() as *const c_char, ffi::SQLITE_TRANSIENT())
261 } else {
262 ("".as_ptr() as *const c_char, ffi::SQLITE_STATIC())
264 };
265 Ok((ptr, len, dtor_info))
266}
267
268fn len_as_c_int(len: usize) -> Result<c_int> {
271 if len >= (c_int::max_value() as usize) {
272 Err(Error::SqliteFailure(
273 ffi::Error::new(ffi::SQLITE_TOOBIG),
274 None,
275 ))
276 } else {
277 Ok(len as c_int)
278 }
279}
280
281#[cfg(unix)]
282fn path_to_cstring(p: &Path) -> Result<CString> {
283 use std::os::unix::ffi::OsStrExt;
284 Ok(CString::new(p.as_os_str().as_bytes())?)
285}
286
287#[cfg(not(unix))]
288fn path_to_cstring(p: &Path) -> Result<CString> {
289 let s = p.to_str().ok_or_else(|| Error::InvalidPath(p.to_owned()))?;
290 Ok(CString::new(s)?)
291}
292
293#[derive(Copy, Clone, Debug)]
295pub enum DatabaseName<'a> {
296 Main,
298
299 Temp,
301
302 Attached(&'a str),
304}
305
306pub const MAIN_DB: DatabaseName<'static> = DatabaseName::Main;
308
309pub const TEMP_DB: DatabaseName<'static> = DatabaseName::Temp;
311
312#[cfg(any(
315 feature = "backup",
316 feature = "blob",
317 feature = "session",
318 feature = "modern_sqlite"
319))]
320impl DatabaseName<'_> {
321 #[inline]
322 fn to_cstring(&self) -> Result<util::SmallCString> {
323 use self::DatabaseName::{Attached, Main, Temp};
324 match *self {
325 Main => str_to_cstring("main"),
326 Temp => str_to_cstring("temp"),
327 Attached(s) => str_to_cstring(s),
328 }
329 }
330}
331
332pub struct Connection {
334 db: RefCell<InnerConnection>,
335 cache: StatementCache,
336 path: Option<PathBuf>,
337}
338
339unsafe impl Send for Connection {}
340
341impl Drop for Connection {
342 #[inline]
343 fn drop(&mut self) {
344 self.flush_prepared_statement_cache();
345 }
346}
347
348impl Connection {
349 #[inline]
371 pub fn open<P: AsRef<Path>>(path: P) -> Result<Connection> {
372 let flags = OpenFlags::default();
373 Connection::open_with_flags(path, flags)
374 }
375
376 #[inline]
382 pub fn open_in_memory() -> Result<Connection> {
383 let flags = OpenFlags::default();
384 Connection::open_in_memory_with_flags(flags)
385 }
386
387 #[inline]
397 pub fn open_with_flags<P: AsRef<Path>>(path: P, flags: OpenFlags) -> Result<Connection> {
398 let c_path = path_to_cstring(path.as_ref())?;
399 InnerConnection::open_with_flags(&c_path, flags, None).map(|db| Connection {
400 db: RefCell::new(db),
401 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
402 path: Some(path.as_ref().to_path_buf()),
403 })
404 }
405
406 #[inline]
417 pub fn open_with_flags_and_vfs<P: AsRef<Path>>(
418 path: P,
419 flags: OpenFlags,
420 vfs: &str,
421 ) -> Result<Connection> {
422 let c_path = path_to_cstring(path.as_ref())?;
423 let c_vfs = str_to_cstring(vfs)?;
424 InnerConnection::open_with_flags(&c_path, flags, Some(&c_vfs)).map(|db| Connection {
425 db: RefCell::new(db),
426 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
427 path: Some(path.as_ref().to_path_buf()),
428 })
429 }
430
431 #[inline]
440 pub fn open_in_memory_with_flags(flags: OpenFlags) -> Result<Connection> {
441 Connection::open_with_flags(":memory:", flags)
442 }
443
444 #[inline]
455 pub fn open_in_memory_with_flags_and_vfs(flags: OpenFlags, vfs: &str) -> Result<Connection> {
456 Connection::open_with_flags_and_vfs(":memory:", flags, vfs)
457 }
458
459 pub fn execute_batch(&self, sql: &str) -> Result<()> {
480 let mut sql = sql;
481 while !sql.is_empty() {
482 let stmt = self.prepare(sql)?;
483 if !stmt.stmt.is_null() && stmt.step()? && cfg!(feature = "extra_check") {
484 return Err(Error::ExecuteReturnedResults);
486 }
487 let tail = stmt.stmt.tail();
488 if tail == 0 || tail >= sql.len() {
489 break;
490 }
491 sql = &sql[tail..];
492 }
493 Ok(())
494 }
495
496 #[inline]
544 pub fn execute<P: Params>(&self, sql: &str, params: P) -> Result<usize> {
545 self.prepare(sql)
546 .and_then(|mut stmt| stmt.check_no_tail().and_then(|_| stmt.execute(params)))
547 }
548
549 #[deprecated = "You can use `execute` with named params now."]
560 pub fn execute_named(&self, sql: &str, params: &[(&str, &dyn ToSql)]) -> Result<usize> {
561 #![allow(deprecated)]
563 self.prepare(sql).and_then(|mut stmt| {
564 stmt.check_no_tail()
565 .and_then(|_| stmt.execute_named(params))
566 })
567 }
568
569 #[inline]
574 pub fn last_insert_rowid(&self) -> i64 {
575 self.db.borrow_mut().last_insert_rowid()
576 }
577
578 #[inline]
606 pub fn query_row<T, P, F>(&self, sql: &str, params: P, f: F) -> Result<T>
607 where
608 P: Params,
609 F: FnOnce(&Row<'_>) -> Result<T>,
610 {
611 let mut stmt = self.prepare(sql)?;
612 stmt.check_no_tail()?;
613 stmt.query_row(params, f)
614 }
615
616 #[deprecated = "You can use `query_row` with named params now."]
631 pub fn query_row_named<T, F>(&self, sql: &str, params: &[(&str, &dyn ToSql)], f: F) -> Result<T>
632 where
633 F: FnOnce(&Row<'_>) -> Result<T>,
634 {
635 self.query_row(sql, params, f)
636 }
637
638 #[inline]
664 pub fn query_row_and_then<T, E, P, F>(&self, sql: &str, params: P, f: F) -> Result<T, E>
665 where
666 P: Params,
667 F: FnOnce(&Row<'_>) -> Result<T, E>,
668 E: convert::From<Error>,
669 {
670 let mut stmt = self.prepare(sql)?;
671 stmt.check_no_tail()?;
672 let mut rows = stmt.query(params)?;
673
674 rows.get_expected_row().map_err(E::from).and_then(|r| f(&r))
675 }
676
677 #[inline]
696 pub fn prepare(&self, sql: &str) -> Result<Statement<'_>> {
697 self.db.borrow_mut().prepare(self, sql)
698 }
699
700 #[inline]
710 pub fn close(self) -> Result<(), (Connection, Error)> {
711 self.flush_prepared_statement_cache();
712 let r = self.db.borrow_mut().close();
713 r.map_err(move |err| (self, err))
714 }
715
716 #[cfg(feature = "load_extension")]
735 #[inline]
736 pub fn load_extension_enable(&self) -> Result<()> {
737 self.db.borrow_mut().enable_load_extension(1)
738 }
739
740 #[cfg(feature = "load_extension")]
748 #[inline]
749 pub fn load_extension_disable(&self) -> Result<()> {
750 self.db.borrow_mut().enable_load_extension(0)
751 }
752
753 #[cfg(feature = "load_extension")]
777 #[inline]
778 pub fn load_extension<P: AsRef<Path>>(
779 &self,
780 dylib_path: P,
781 entry_point: Option<&str>,
782 ) -> Result<()> {
783 self.db
784 .borrow_mut()
785 .load_extension(dylib_path.as_ref(), entry_point)
786 }
787
788 #[inline]
802 pub unsafe fn handle(&self) -> *mut ffi::sqlite3 {
803 self.db.borrow().db()
804 }
805
806 #[inline]
815 pub unsafe fn from_handle(db: *mut ffi::sqlite3) -> Result<Connection> {
816 let db_path = db_filename(db);
817 let db = InnerConnection::new(db, false);
818 Ok(Connection {
819 db: RefCell::new(db),
820 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
821 path: db_path,
822 })
823 }
824
825 #[inline]
828 pub fn get_interrupt_handle(&self) -> InterruptHandle {
829 self.db.borrow().get_interrupt_handle()
830 }
831
832 #[inline]
833 fn decode_result(&self, code: c_int) -> Result<()> {
834 self.db.borrow_mut().decode_result(code)
835 }
836
837 #[inline]
841 fn changes(&self) -> usize {
842 self.db.borrow_mut().changes()
843 }
844
845 #[inline]
848 pub fn is_autocommit(&self) -> bool {
849 self.db.borrow().is_autocommit()
850 }
851
852 #[inline]
854 #[cfg(feature = "modern_sqlite")] pub fn is_busy(&self) -> bool {
856 self.db.borrow().is_busy()
857 }
858}
859
860impl fmt::Debug for Connection {
861 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
862 f.debug_struct("Connection")
863 .field("path", &self.path)
864 .finish()
865 }
866}
867
868#[derive(Debug)]
886pub struct Batch<'conn, 'sql> {
887 conn: &'conn Connection,
888 sql: &'sql str,
889 tail: usize,
890}
891
892impl<'conn, 'sql> Batch<'conn, 'sql> {
893 pub fn new(conn: &'conn Connection, sql: &'sql str) -> Batch<'conn, 'sql> {
895 Batch { conn, sql, tail: 0 }
896 }
897
898 #[allow(clippy::should_implement_trait)] pub fn next(&mut self) -> Result<Option<Statement<'conn>>> {
903 while self.tail < self.sql.len() {
904 let sql = &self.sql[self.tail..];
905 let next = self.conn.prepare(sql)?;
906 let tail = next.stmt.tail();
907 if tail == 0 {
908 self.tail = self.sql.len();
909 } else {
910 self.tail += tail;
911 }
912 if next.stmt.is_null() {
913 continue;
914 }
915 return Ok(Some(next));
916 }
917 Ok(None)
918 }
919}
920
921impl<'conn> Iterator for Batch<'conn, '_> {
922 type Item = Result<Statement<'conn>>;
923
924 fn next(&mut self) -> Option<Result<Statement<'conn>>> {
925 self.next().transpose()
926 }
927}
928
929bitflags::bitflags! {
930 #[repr(C)]
933 pub struct OpenFlags: ::std::os::raw::c_int {
934 const SQLITE_OPEN_READ_ONLY = ffi::SQLITE_OPEN_READONLY;
937 const SQLITE_OPEN_READ_WRITE = ffi::SQLITE_OPEN_READWRITE;
941 const SQLITE_OPEN_CREATE = ffi::SQLITE_OPEN_CREATE;
943 const SQLITE_OPEN_URI = 0x0000_0040;
945 const SQLITE_OPEN_MEMORY = 0x0000_0080;
947 const SQLITE_OPEN_NO_MUTEX = ffi::SQLITE_OPEN_NOMUTEX;
949 const SQLITE_OPEN_FULL_MUTEX = ffi::SQLITE_OPEN_FULLMUTEX;
951 const SQLITE_OPEN_SHARED_CACHE = 0x0002_0000;
953 const SQLITE_OPEN_PRIVATE_CACHE = 0x0004_0000;
955 const SQLITE_OPEN_NOFOLLOW = 0x0100_0000;
957 }
958}
959
960impl Default for OpenFlags {
961 fn default() -> OpenFlags {
962 OpenFlags::SQLITE_OPEN_READ_WRITE
963 | OpenFlags::SQLITE_OPEN_CREATE
964 | OpenFlags::SQLITE_OPEN_NO_MUTEX
965 | OpenFlags::SQLITE_OPEN_URI
966 }
967}
968
969pub unsafe fn bypass_sqlite_initialization() {
989 BYPASS_SQLITE_INIT.store(true, Ordering::Relaxed);
990}
991
992pub unsafe fn bypass_sqlite_version_check() {
1003 #[cfg(not(feature = "bundled"))]
1004 inner_connection::BYPASS_VERSION_CHECK.store(true, Ordering::Relaxed);
1005}
1006
1007pub struct InterruptHandle {
1009 db_lock: Arc<Mutex<*mut ffi::sqlite3>>,
1010}
1011
1012unsafe impl Send for InterruptHandle {}
1013unsafe impl Sync for InterruptHandle {}
1014
1015impl InterruptHandle {
1016 pub fn interrupt(&self) {
1019 let db_handle = self.db_lock.lock().unwrap();
1020 if !db_handle.is_null() {
1021 #[cfg(not(any(
1022 feature = "loadable_extension",
1023 feature = "loadable_extension_embedded"
1024 )))] unsafe {
1026 ffi::sqlite3_interrupt(*db_handle)
1027 }
1028 }
1029 }
1030}
1031
1032#[cfg(feature = "modern_sqlite")] unsafe fn db_filename(db: *mut ffi::sqlite3) -> Option<PathBuf> {
1034 let db_name = DatabaseName::Main.to_cstring().unwrap();
1035 let db_filename = ffi::sqlite3_db_filename(db, db_name.as_ptr());
1036 if db_filename.is_null() {
1037 None
1038 } else {
1039 CStr::from_ptr(db_filename).to_str().ok().map(PathBuf::from)
1040 }
1041}
1042#[cfg(not(feature = "modern_sqlite"))]
1043unsafe fn db_filename(_: *mut ffi::sqlite3) -> Option<PathBuf> {
1044 None
1045}
1046
1047#[cfg(doctest)]
1048doc_comment::doctest!("../README.md");
1049
1050#[cfg(test)]
1051mod test {
1052 use super::*;
1053 use crate::ffi;
1054 use fallible_iterator::FallibleIterator;
1055 use std::error::Error as StdError;
1056 use std::fmt;
1057
1058 #[allow(dead_code, unconditional_recursion)]
1062 fn ensure_send<T: Send>() {
1063 ensure_send::<Connection>();
1064 ensure_send::<InterruptHandle>();
1065 }
1066
1067 #[allow(dead_code, unconditional_recursion)]
1068 fn ensure_sync<T: Sync>() {
1069 ensure_sync::<InterruptHandle>();
1070 }
1071
1072 pub fn checked_memory_handle() -> Connection {
1073 Connection::open_in_memory().unwrap()
1074 }
1075
1076 #[test]
1077 fn test_concurrent_transactions_busy_commit() -> Result<()> {
1078 use std::time::Duration;
1079 let tmp = tempfile::tempdir().unwrap();
1080 let path = tmp.path().join("transactions.db3");
1081
1082 Connection::open(&path)?.execute_batch(
1083 "
1084 BEGIN; CREATE TABLE foo(x INTEGER);
1085 INSERT INTO foo VALUES(42); END;",
1086 )?;
1087
1088 let mut db1 = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_WRITE)?;
1089 let mut db2 = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_ONLY)?;
1090
1091 db1.busy_timeout(Duration::from_millis(0))?;
1092 db2.busy_timeout(Duration::from_millis(0))?;
1093
1094 {
1095 let tx1 = db1.transaction()?;
1096 let tx2 = db2.transaction()?;
1097
1098 tx1.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))?;
1100 tx2.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))?;
1101
1102 tx1.execute("INSERT INTO foo VALUES(?1)", &[&1])?;
1103 let _ = tx2.execute("INSERT INTO foo VALUES(?1)", [2]);
1104
1105 let _ = tx1.commit();
1106 let _ = tx2.commit();
1107 }
1108
1109 let _ = db1
1110 .transaction()
1111 .expect("commit should have closed transaction");
1112 let _ = db2
1113 .transaction()
1114 .expect("commit should have closed transaction");
1115 Ok(())
1116 }
1117
1118 #[test]
1119 fn test_persistence() -> Result<()> {
1120 let temp_dir = tempfile::tempdir().unwrap();
1121 let path = temp_dir.path().join("test.db3");
1122
1123 {
1124 let db = Connection::open(&path)?;
1125 let sql = "BEGIN;
1126 CREATE TABLE foo(x INTEGER);
1127 INSERT INTO foo VALUES(42);
1128 END;";
1129 db.execute_batch(sql)?;
1130 }
1131
1132 let path_string = path.to_str().unwrap();
1133 let db = Connection::open(&path_string)?;
1134 let the_answer: Result<i64> = db.query_row("SELECT x FROM foo", [], |r| r.get(0));
1135
1136 assert_eq!(42i64, the_answer?);
1137 Ok(())
1138 }
1139
1140 #[test]
1141 fn test_open() {
1142 assert!(Connection::open_in_memory().is_ok());
1143
1144 let db = checked_memory_handle();
1145 assert!(db.close().is_ok());
1146 }
1147
1148 #[test]
1149 fn test_open_failure() {
1150 let filename = "no_such_file.db";
1151 let result = Connection::open_with_flags(filename, OpenFlags::SQLITE_OPEN_READ_ONLY);
1152 assert!(!result.is_ok());
1153 let err = result.err().unwrap();
1154 if let Error::SqliteFailure(e, Some(msg)) = err {
1155 assert_eq!(ErrorCode::CannotOpen, e.code);
1156 assert_eq!(ffi::SQLITE_CANTOPEN, e.extended_code);
1157 assert!(
1158 msg.contains(filename),
1159 "error message '{}' does not contain '{}'",
1160 msg,
1161 filename
1162 );
1163 } else {
1164 panic!("SqliteFailure expected");
1165 }
1166 }
1167
1168 #[cfg(unix)]
1169 #[test]
1170 fn test_invalid_unicode_file_names() -> Result<()> {
1171 use std::ffi::OsStr;
1172 use std::fs::File;
1173 use std::os::unix::ffi::OsStrExt;
1174 let temp_dir = tempfile::tempdir().unwrap();
1175
1176 let path = temp_dir.path();
1177 if File::create(path.join(OsStr::from_bytes(&[0xFE]))).is_err() {
1178 return Ok(());
1180 }
1181 let db_path = path.join(OsStr::from_bytes(&[0xFF]));
1182 {
1183 let db = Connection::open(&db_path)?;
1184 let sql = "BEGIN;
1185 CREATE TABLE foo(x INTEGER);
1186 INSERT INTO foo VALUES(42);
1187 END;";
1188 db.execute_batch(sql)?;
1189 }
1190
1191 let db = Connection::open(&db_path)?;
1192 let the_answer: Result<i64> = db.query_row("SELECT x FROM foo", [], |r| r.get(0));
1193
1194 assert_eq!(42i64, the_answer?);
1195 Ok(())
1196 }
1197
1198 #[test]
1199 fn test_close_retry() -> Result<()> {
1200 let db = checked_memory_handle();
1201
1202 let raw_stmt = {
1206 use super::str_to_cstring;
1207 use std::os::raw::c_int;
1208 use std::ptr;
1209
1210 let raw_db = db.db.borrow_mut().db;
1211 let sql = "SELECT 1";
1212 let mut raw_stmt: *mut ffi::sqlite3_stmt = ptr::null_mut();
1213 let cstring = str_to_cstring(sql)?;
1214 let rc = unsafe {
1215 ffi::sqlite3_prepare_v2(
1216 raw_db,
1217 cstring.as_ptr(),
1218 (sql.len() + 1) as c_int,
1219 &mut raw_stmt,
1220 ptr::null_mut(),
1221 )
1222 };
1223 assert_eq!(rc, ffi::SQLITE_OK);
1224 raw_stmt
1225 };
1226
1227 let (db, _) = db.close().unwrap_err();
1230 let (db, _) = db.close().unwrap_err();
1231 let (db, _) = db.close().unwrap_err();
1232
1233 assert_eq!(ffi::SQLITE_OK, unsafe { ffi::sqlite3_finalize(raw_stmt) });
1235
1236 db.close().unwrap();
1237 Ok(())
1238 }
1239
1240 #[test]
1241 fn test_open_with_flags() {
1242 for bad_flags in &[
1243 OpenFlags::empty(),
1244 OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_READ_WRITE,
1245 OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_CREATE,
1246 ] {
1247 assert!(Connection::open_in_memory_with_flags(*bad_flags).is_err());
1248 }
1249 }
1250
1251 #[test]
1252 fn test_execute_batch() -> Result<()> {
1253 let db = checked_memory_handle();
1254 let sql = "BEGIN;
1255 CREATE TABLE foo(x INTEGER);
1256 INSERT INTO foo VALUES(1);
1257 INSERT INTO foo VALUES(2);
1258 INSERT INTO foo VALUES(3);
1259 INSERT INTO foo VALUES(4);
1260 END;";
1261 db.execute_batch(sql)?;
1262
1263 db.execute_batch("UPDATE foo SET x = 3 WHERE x < 3")?;
1264
1265 assert!(db.execute_batch("INVALID SQL").is_err());
1266 Ok(())
1267 }
1268
1269 #[test]
1270 fn test_execute() -> Result<()> {
1271 let db = checked_memory_handle();
1272 db.execute_batch("CREATE TABLE foo(x INTEGER)")?;
1273
1274 assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?)", [1i32])?);
1275 assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?)", [2i32])?);
1276
1277 assert_eq!(
1278 3i32,
1279 db.query_row::<i32, _, _>("SELECT SUM(x) FROM foo", [], |r| r.get(0))?
1280 );
1281 Ok(())
1282 }
1283
1284 #[test]
1285 #[cfg(feature = "extra_check")]
1286 fn test_execute_select() {
1287 let db = checked_memory_handle();
1288 let err = db.execute("SELECT 1 WHERE 1 < ?", [1i32]).unwrap_err();
1289 if err != Error::ExecuteReturnedResults {
1290 panic!("Unexpected error: {}", err);
1291 }
1292 }
1293
1294 #[test]
1295 #[cfg(feature = "extra_check")]
1296 fn test_execute_multiple() {
1297 let db = checked_memory_handle();
1298 let err = db
1299 .execute(
1300 "CREATE TABLE foo(x INTEGER); CREATE TABLE foo(x INTEGER)",
1301 [],
1302 )
1303 .unwrap_err();
1304 match err {
1305 Error::MultipleStatement => (),
1306 _ => panic!("Unexpected error: {}", err),
1307 }
1308 }
1309
1310 #[test]
1311 fn test_prepare_column_names() -> Result<()> {
1312 let db = checked_memory_handle();
1313 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1314
1315 let stmt = db.prepare("SELECT * FROM foo")?;
1316 assert_eq!(stmt.column_count(), 1);
1317 assert_eq!(stmt.column_names(), vec!["x"]);
1318
1319 let stmt = db.prepare("SELECT x AS a, x AS b FROM foo")?;
1320 assert_eq!(stmt.column_count(), 2);
1321 assert_eq!(stmt.column_names(), vec!["a", "b"]);
1322 Ok(())
1323 }
1324
1325 #[test]
1326 fn test_prepare_execute() -> Result<()> {
1327 let db = checked_memory_handle();
1328 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1329
1330 let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?)")?;
1331 assert_eq!(insert_stmt.execute([1i32])?, 1);
1332 assert_eq!(insert_stmt.execute([2i32])?, 1);
1333 assert_eq!(insert_stmt.execute([3i32])?, 1);
1334
1335 assert_eq!(insert_stmt.execute(["hello".to_string()])?, 1);
1336 assert_eq!(insert_stmt.execute(["goodbye".to_string()])?, 1);
1337 assert_eq!(insert_stmt.execute([types::Null])?, 1);
1338
1339 let mut update_stmt = db.prepare("UPDATE foo SET x=? WHERE x<?")?;
1340 assert_eq!(update_stmt.execute([3i32, 3i32])?, 2);
1341 assert_eq!(update_stmt.execute([3i32, 3i32])?, 0);
1342 assert_eq!(update_stmt.execute([8i32, 8i32])?, 3);
1343 Ok(())
1344 }
1345
1346 #[test]
1347 fn test_prepare_query() -> Result<()> {
1348 let db = checked_memory_handle();
1349 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1350
1351 let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?)")?;
1352 assert_eq!(insert_stmt.execute([1i32])?, 1);
1353 assert_eq!(insert_stmt.execute([2i32])?, 1);
1354 assert_eq!(insert_stmt.execute([3i32])?, 1);
1355
1356 let mut query = db.prepare("SELECT x FROM foo WHERE x < ? ORDER BY x DESC")?;
1357 {
1358 let mut rows = query.query([4i32])?;
1359 let mut v = Vec::<i32>::new();
1360
1361 while let Some(row) = rows.next()? {
1362 v.push(row.get(0)?);
1363 }
1364
1365 assert_eq!(v, [3i32, 2, 1]);
1366 }
1367
1368 {
1369 let mut rows = query.query([3i32])?;
1370 let mut v = Vec::<i32>::new();
1371
1372 while let Some(row) = rows.next()? {
1373 v.push(row.get(0)?);
1374 }
1375
1376 assert_eq!(v, [2i32, 1]);
1377 }
1378 Ok(())
1379 }
1380
1381 #[test]
1382 fn test_query_map() -> Result<()> {
1383 let db = checked_memory_handle();
1384 let sql = "BEGIN;
1385 CREATE TABLE foo(x INTEGER, y TEXT);
1386 INSERT INTO foo VALUES(4, \"hello\");
1387 INSERT INTO foo VALUES(3, \", \");
1388 INSERT INTO foo VALUES(2, \"world\");
1389 INSERT INTO foo VALUES(1, \"!\");
1390 END;";
1391 db.execute_batch(sql)?;
1392
1393 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1394 let results: Result<Vec<String>> = query.query([])?.map(|row| row.get(1)).collect();
1395
1396 assert_eq!(results?.concat(), "hello, world!");
1397 Ok(())
1398 }
1399
1400 #[test]
1401 fn test_query_row() -> Result<()> {
1402 let db = checked_memory_handle();
1403 let sql = "BEGIN;
1404 CREATE TABLE foo(x INTEGER);
1405 INSERT INTO foo VALUES(1);
1406 INSERT INTO foo VALUES(2);
1407 INSERT INTO foo VALUES(3);
1408 INSERT INTO foo VALUES(4);
1409 END;";
1410 db.execute_batch(sql)?;
1411
1412 assert_eq!(
1413 10i64,
1414 db.query_row::<i64, _, _>("SELECT SUM(x) FROM foo", [], |r| r.get(0))?
1415 );
1416
1417 let result: Result<i64> = db.query_row("SELECT x FROM foo WHERE x > 5", [], |r| r.get(0));
1418 match result.unwrap_err() {
1419 Error::QueryReturnedNoRows => (),
1420 err => panic!("Unexpected error {}", err),
1421 }
1422
1423 let bad_query_result = db.query_row("NOT A PROPER QUERY; test123", [], |_| Ok(()));
1424
1425 assert!(bad_query_result.is_err());
1426 Ok(())
1427 }
1428
1429 #[test]
1430 fn test_optional() -> Result<()> {
1431 let db = checked_memory_handle();
1432
1433 let result: Result<i64> = db.query_row("SELECT 1 WHERE 0 <> 0", [], |r| r.get(0));
1434 let result = result.optional();
1435 match result? {
1436 None => (),
1437 _ => panic!("Unexpected result"),
1438 }
1439
1440 let result: Result<i64> = db.query_row("SELECT 1 WHERE 0 == 0", [], |r| r.get(0));
1441 let result = result.optional();
1442 match result? {
1443 Some(1) => (),
1444 _ => panic!("Unexpected result"),
1445 }
1446
1447 let bad_query_result: Result<i64> = db.query_row("NOT A PROPER QUERY", [], |r| r.get(0));
1448 let bad_query_result = bad_query_result.optional();
1449 assert!(bad_query_result.is_err());
1450 Ok(())
1451 }
1452
1453 #[test]
1454 fn test_pragma_query_row() -> Result<()> {
1455 let db = checked_memory_handle();
1456
1457 assert_eq!(
1458 "memory",
1459 db.query_row::<String, _, _>("PRAGMA journal_mode", [], |r| r.get(0))?
1460 );
1461 assert_eq!(
1462 "off",
1463 db.query_row::<String, _, _>("PRAGMA journal_mode=off", [], |r| r.get(0))?
1464 );
1465 Ok(())
1466 }
1467
1468 #[test]
1469 fn test_prepare_failures() -> Result<()> {
1470 let db = checked_memory_handle();
1471 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1472
1473 let err = db.prepare("SELECT * FROM does_not_exist").unwrap_err();
1474 assert!(format!("{}", err).contains("does_not_exist"));
1475 Ok(())
1476 }
1477
1478 #[test]
1479 fn test_last_insert_rowid() -> Result<()> {
1480 let db = checked_memory_handle();
1481 db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)")?;
1482 db.execute_batch("INSERT INTO foo DEFAULT VALUES")?;
1483
1484 assert_eq!(db.last_insert_rowid(), 1);
1485
1486 let mut stmt = db.prepare("INSERT INTO foo DEFAULT VALUES")?;
1487 for _ in 0i32..9 {
1488 stmt.execute([])?;
1489 }
1490 assert_eq!(db.last_insert_rowid(), 10);
1491 Ok(())
1492 }
1493
1494 #[test]
1495 fn test_is_autocommit() {
1496 let db = checked_memory_handle();
1497 assert!(
1498 db.is_autocommit(),
1499 "autocommit expected to be active by default"
1500 );
1501 }
1502
1503 #[test]
1504 #[cfg(feature = "modern_sqlite")]
1505 fn test_is_busy() -> Result<()> {
1506 let db = checked_memory_handle();
1507 assert!(!db.is_busy());
1508 let mut stmt = db.prepare("PRAGMA schema_version")?;
1509 assert!(!db.is_busy());
1510 {
1511 let mut rows = stmt.query([])?;
1512 assert!(!db.is_busy());
1513 let row = rows.next()?;
1514 assert!(db.is_busy());
1515 assert!(row.is_some());
1516 }
1517 assert!(!db.is_busy());
1518 Ok(())
1519 }
1520
1521 #[test]
1522 fn test_statement_debugging() -> Result<()> {
1523 let db = checked_memory_handle();
1524 let query = "SELECT 12345";
1525 let stmt = db.prepare(query)?;
1526
1527 assert!(format!("{:?}", stmt).contains(query));
1528 Ok(())
1529 }
1530
1531 #[test]
1532 fn test_notnull_constraint_error() -> Result<()> {
1533 #[cfg(feature = "modern_sqlite")]
1536 fn check_extended_code(extended_code: c_int) {
1537 assert_eq!(extended_code, ffi::SQLITE_CONSTRAINT_NOTNULL);
1538 }
1539 #[cfg(not(feature = "modern_sqlite"))]
1540 fn check_extended_code(_extended_code: c_int) {}
1541
1542 let db = checked_memory_handle();
1543 db.execute_batch("CREATE TABLE foo(x NOT NULL)")?;
1544
1545 let result = db.execute("INSERT INTO foo (x) VALUES (NULL)", []);
1546 assert!(result.is_err());
1547
1548 match result.unwrap_err() {
1549 Error::SqliteFailure(err, _) => {
1550 assert_eq!(err.code, ErrorCode::ConstraintViolation);
1551 check_extended_code(err.extended_code);
1552 }
1553 err => panic!("Unexpected error {}", err),
1554 }
1555 Ok(())
1556 }
1557
1558 #[test]
1559 fn test_version_string() {
1560 let n = version_number();
1561 let major = n / 1_000_000;
1562 let minor = (n % 1_000_000) / 1_000;
1563 let patch = n % 1_000;
1564
1565 assert!(version().contains(&format!("{}.{}.{}", major, minor, patch)));
1566 }
1567
1568 #[test]
1569 #[cfg(feature = "functions")]
1570 fn test_interrupt() -> Result<()> {
1571 let db = checked_memory_handle();
1572
1573 let interrupt_handle = db.get_interrupt_handle();
1574
1575 db.create_scalar_function(
1576 "interrupt",
1577 0,
1578 crate::functions::FunctionFlags::default(),
1579 move |_| {
1580 interrupt_handle.interrupt();
1581 Ok(0)
1582 },
1583 )?;
1584
1585 let mut stmt =
1586 db.prepare("SELECT interrupt() FROM (SELECT 1 UNION SELECT 2 UNION SELECT 3)")?;
1587
1588 let result: Result<Vec<i32>> = stmt.query([])?.map(|r| r.get(0)).collect();
1589
1590 match result.unwrap_err() {
1591 Error::SqliteFailure(err, _) => {
1592 assert_eq!(err.code, ErrorCode::OperationInterrupted);
1593 }
1594 err => {
1595 panic!("Unexpected error {}", err);
1596 }
1597 }
1598 Ok(())
1599 }
1600
1601 #[test]
1602 fn test_interrupt_close() {
1603 let db = checked_memory_handle();
1604 let handle = db.get_interrupt_handle();
1605 handle.interrupt();
1606 db.close().unwrap();
1607 handle.interrupt();
1608
1609 let db_guard = handle.db_lock.lock().unwrap();
1611 assert!(db_guard.is_null());
1612 }
1616
1617 #[test]
1618 fn test_get_raw() -> Result<()> {
1619 let db = checked_memory_handle();
1620 db.execute_batch("CREATE TABLE foo(i, x);")?;
1621 let vals = ["foobar", "1234", "qwerty"];
1622 let mut insert_stmt = db.prepare("INSERT INTO foo(i, x) VALUES(?, ?)")?;
1623 for (i, v) in vals.iter().enumerate() {
1624 let i_to_insert = i as i64;
1625 assert_eq!(insert_stmt.execute(params![i_to_insert, v])?, 1);
1626 }
1627
1628 let mut query = db.prepare("SELECT i, x FROM foo")?;
1629 let mut rows = query.query([])?;
1630
1631 while let Some(row) = rows.next()? {
1632 let i = row.get_ref(0)?.as_i64()?;
1633 let expect = vals[i as usize];
1634 let x = row.get_ref("x")?.as_str()?;
1635 assert_eq!(x, expect);
1636 }
1637
1638 let mut query = db.prepare("SELECT x FROM foo")?;
1639 let rows = query.query_map([], |row| {
1640 let x = row.get_ref(0)?.as_str()?; Ok(x[..].to_owned())
1642 })?;
1643
1644 for (i, row) in rows.enumerate() {
1645 assert_eq!(row?, vals[i]);
1646 }
1647 Ok(())
1648 }
1649
1650 #[test]
1651 fn test_from_handle() -> Result<()> {
1652 let db = checked_memory_handle();
1653 let handle = unsafe { db.handle() };
1654 {
1655 let db = unsafe { Connection::from_handle(handle) }?;
1656 db.execute_batch("PRAGMA VACUUM")?;
1657 }
1658 db.close().unwrap();
1659 Ok(())
1660 }
1661
1662 mod query_and_then_tests {
1663
1664 use super::*;
1665
1666 #[derive(Debug)]
1667 enum CustomError {
1668 SomeError,
1669 Sqlite(Error),
1670 }
1671
1672 impl fmt::Display for CustomError {
1673 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1674 match *self {
1675 CustomError::SomeError => write!(f, "my custom error"),
1676 CustomError::Sqlite(ref se) => write!(f, "my custom error: {}", se),
1677 }
1678 }
1679 }
1680
1681 impl StdError for CustomError {
1682 fn description(&self) -> &str {
1683 "my custom error"
1684 }
1685
1686 fn cause(&self) -> Option<&dyn StdError> {
1687 match *self {
1688 CustomError::SomeError => None,
1689 CustomError::Sqlite(ref se) => Some(se),
1690 }
1691 }
1692 }
1693
1694 impl From<Error> for CustomError {
1695 fn from(se: Error) -> CustomError {
1696 CustomError::Sqlite(se)
1697 }
1698 }
1699
1700 type CustomResult<T> = Result<T, CustomError>;
1701
1702 #[test]
1703 fn test_query_and_then() -> Result<()> {
1704 let db = checked_memory_handle();
1705 let sql = "BEGIN;
1706 CREATE TABLE foo(x INTEGER, y TEXT);
1707 INSERT INTO foo VALUES(4, \"hello\");
1708 INSERT INTO foo VALUES(3, \", \");
1709 INSERT INTO foo VALUES(2, \"world\");
1710 INSERT INTO foo VALUES(1, \"!\");
1711 END;";
1712 db.execute_batch(sql)?;
1713
1714 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1715 let results: Result<Vec<String>> =
1716 query.query_and_then([], |row| row.get(1))?.collect();
1717
1718 assert_eq!(results?.concat(), "hello, world!");
1719 Ok(())
1720 }
1721
1722 #[test]
1723 fn test_query_and_then_fails() -> Result<()> {
1724 let db = checked_memory_handle();
1725 let sql = "BEGIN;
1726 CREATE TABLE foo(x INTEGER, y TEXT);
1727 INSERT INTO foo VALUES(4, \"hello\");
1728 INSERT INTO foo VALUES(3, \", \");
1729 INSERT INTO foo VALUES(2, \"world\");
1730 INSERT INTO foo VALUES(1, \"!\");
1731 END;";
1732 db.execute_batch(sql)?;
1733
1734 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1735 let bad_type: Result<Vec<f64>> = query.query_and_then([], |row| row.get(1))?.collect();
1736
1737 match bad_type.unwrap_err() {
1738 Error::InvalidColumnType(..) => (),
1739 err => panic!("Unexpected error {}", err),
1740 }
1741
1742 let bad_idx: Result<Vec<String>> =
1743 query.query_and_then([], |row| row.get(3))?.collect();
1744
1745 match bad_idx.unwrap_err() {
1746 Error::InvalidColumnIndex(_) => (),
1747 err => panic!("Unexpected error {}", err),
1748 }
1749 Ok(())
1750 }
1751
1752 #[test]
1753 fn test_query_and_then_custom_error() -> CustomResult<()> {
1754 let db = checked_memory_handle();
1755 let sql = "BEGIN;
1756 CREATE TABLE foo(x INTEGER, y TEXT);
1757 INSERT INTO foo VALUES(4, \"hello\");
1758 INSERT INTO foo VALUES(3, \", \");
1759 INSERT INTO foo VALUES(2, \"world\");
1760 INSERT INTO foo VALUES(1, \"!\");
1761 END;";
1762 db.execute_batch(sql)?;
1763
1764 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1765 let results: CustomResult<Vec<String>> = query
1766 .query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite))?
1767 .collect();
1768
1769 assert_eq!(results?.concat(), "hello, world!");
1770 Ok(())
1771 }
1772
1773 #[test]
1774 fn test_query_and_then_custom_error_fails() -> Result<()> {
1775 let db = checked_memory_handle();
1776 let sql = "BEGIN;
1777 CREATE TABLE foo(x INTEGER, y TEXT);
1778 INSERT INTO foo VALUES(4, \"hello\");
1779 INSERT INTO foo VALUES(3, \", \");
1780 INSERT INTO foo VALUES(2, \"world\");
1781 INSERT INTO foo VALUES(1, \"!\");
1782 END;";
1783 db.execute_batch(sql)?;
1784
1785 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1786 let bad_type: CustomResult<Vec<f64>> = query
1787 .query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite))?
1788 .collect();
1789
1790 match bad_type.unwrap_err() {
1791 CustomError::Sqlite(Error::InvalidColumnType(..)) => (),
1792 err => panic!("Unexpected error {}", err),
1793 }
1794
1795 let bad_idx: CustomResult<Vec<String>> = query
1796 .query_and_then([], |row| row.get(3).map_err(CustomError::Sqlite))?
1797 .collect();
1798
1799 match bad_idx.unwrap_err() {
1800 CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
1801 err => panic!("Unexpected error {}", err),
1802 }
1803
1804 let non_sqlite_err: CustomResult<Vec<String>> = query
1805 .query_and_then([], |_| Err(CustomError::SomeError))?
1806 .collect();
1807
1808 match non_sqlite_err.unwrap_err() {
1809 CustomError::SomeError => (),
1810 err => panic!("Unexpected error {}", err),
1811 }
1812 Ok(())
1813 }
1814
1815 #[test]
1816 fn test_query_row_and_then_custom_error() -> CustomResult<()> {
1817 let db = checked_memory_handle();
1818 let sql = "BEGIN;
1819 CREATE TABLE foo(x INTEGER, y TEXT);
1820 INSERT INTO foo VALUES(4, \"hello\");
1821 END;";
1822 db.execute_batch(sql)?;
1823
1824 let query = "SELECT x, y FROM foo ORDER BY x DESC";
1825 let results: CustomResult<String> =
1826 db.query_row_and_then(query, [], |row| row.get(1).map_err(CustomError::Sqlite));
1827
1828 assert_eq!(results?, "hello");
1829 Ok(())
1830 }
1831
1832 #[test]
1833 fn test_query_row_and_then_custom_error_fails() -> Result<()> {
1834 let db = checked_memory_handle();
1835 let sql = "BEGIN;
1836 CREATE TABLE foo(x INTEGER, y TEXT);
1837 INSERT INTO foo VALUES(4, \"hello\");
1838 END;";
1839 db.execute_batch(sql)?;
1840
1841 let query = "SELECT x, y FROM foo ORDER BY x DESC";
1842 let bad_type: CustomResult<f64> =
1843 db.query_row_and_then(query, [], |row| row.get(1).map_err(CustomError::Sqlite));
1844
1845 match bad_type.unwrap_err() {
1846 CustomError::Sqlite(Error::InvalidColumnType(..)) => (),
1847 err => panic!("Unexpected error {}", err),
1848 }
1849
1850 let bad_idx: CustomResult<String> =
1851 db.query_row_and_then(query, [], |row| row.get(3).map_err(CustomError::Sqlite));
1852
1853 match bad_idx.unwrap_err() {
1854 CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
1855 err => panic!("Unexpected error {}", err),
1856 }
1857
1858 let non_sqlite_err: CustomResult<String> =
1859 db.query_row_and_then(query, [], |_| Err(CustomError::SomeError));
1860
1861 match non_sqlite_err.unwrap_err() {
1862 CustomError::SomeError => (),
1863 err => panic!("Unexpected error {}", err),
1864 }
1865 Ok(())
1866 }
1867 }
1868
1869 #[test]
1870 fn test_dynamic() -> Result<()> {
1871 let db = checked_memory_handle();
1872 let sql = "BEGIN;
1873 CREATE TABLE foo(x INTEGER, y TEXT);
1874 INSERT INTO foo VALUES(4, \"hello\");
1875 END;";
1876 db.execute_batch(sql)?;
1877
1878 db.query_row("SELECT * FROM foo", [], |r| {
1879 assert_eq!(2, r.column_count());
1880 Ok(())
1881 })
1882 }
1883 #[test]
1884 fn test_dyn_box() -> Result<()> {
1885 let db = checked_memory_handle();
1886 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1887 let b: Box<dyn ToSql> = Box::new(5);
1888 db.execute("INSERT INTO foo VALUES(?)", [b])?;
1889 db.query_row("SELECT x FROM foo", [], |r| {
1890 assert_eq!(5, r.get_unwrap::<_, i32>(0));
1891 Ok(())
1892 })
1893 }
1894
1895 #[test]
1896 fn test_params() -> Result<()> {
1897 let db = checked_memory_handle();
1898 db.query_row(
1899 "SELECT
1900 ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
1901 ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
1902 ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
1903 ?, ?, ?, ?;",
1904 params![
1905 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,
1906 1, 1, 1, 1, 1, 1,
1907 ],
1908 |r| {
1909 assert_eq!(1, r.get_unwrap::<_, i32>(0));
1910 Ok(())
1911 },
1912 )
1913 }
1914
1915 #[test]
1916 #[cfg(not(feature = "extra_check"))]
1917 fn test_alter_table() -> Result<()> {
1918 let db = checked_memory_handle();
1919 db.execute_batch("CREATE TABLE x(t);")?;
1920 db.execute("ALTER TABLE x RENAME TO y;", [])?;
1922 Ok(())
1923 }
1924
1925 #[test]
1926 fn test_batch() -> Result<()> {
1927 let db = checked_memory_handle();
1928 let sql = r"
1929 CREATE TABLE tbl1 (col);
1930 CREATE TABLE tbl2 (col);
1931 ";
1932 let batch = Batch::new(&db, sql);
1933 for stmt in batch {
1934 let mut stmt = stmt?;
1935 stmt.execute([])?;
1936 }
1937 Ok(())
1938 }
1939}