1#![warn(missing_docs)]
57
58pub use libduckdb_sys as ffi;
59
60use std::{
61 cell::RefCell,
62 convert,
63 ffi::CString,
64 fmt,
65 path::{Path, PathBuf},
66 result, str,
67};
68
69use crate::{cache::StatementCache, inner_connection::InnerConnection, raw_statement::RawStatement, types::ValueRef};
70
71#[cfg(feature = "r2d2")]
72pub use crate::r2d2::DuckdbConnectionManager;
73pub use crate::{
74 appender::Appender,
75 appender_params::{appender_params_from_iter, AppenderParams, AppenderParamsFromIter},
76 arrow_batch::{Arrow, ArrowStream},
77 cache::CachedStatement,
78 column::Column,
79 config::{AccessMode, Config, DefaultNullOrder, DefaultOrder},
80 error::Error,
81 ffi::ErrorCode,
82 params::{params_from_iter, Params, ParamsFromIter},
83 row::{AndThenRows, Map, MappedRows, Row, RowIndex, Rows},
84 statement::Statement,
85 transaction::{DropBehavior, Savepoint, Transaction, TransactionBehavior},
86 types::ToSql,
87};
88#[cfg(feature = "polars")]
89pub use polars_dataframe::Polars;
90
91pub use arrow;
93#[cfg(feature = "polars")]
94pub use polars;
95#[cfg(feature = "polars")]
96pub use polars_arrow as arrow2;
97
98pub mod core;
100
101#[macro_use]
102mod error;
103mod appender;
104mod appender_params;
105mod arrow_batch;
106mod arrow_scan;
107mod cache;
108mod column;
109mod config;
110mod inner_connection;
111mod params;
112#[cfg(feature = "polars")]
113mod polars_dataframe;
114mod pragma;
115#[cfg(feature = "r2d2")]
116mod r2d2;
117mod raw_statement;
118mod row;
119mod statement;
120mod transaction;
121
122#[cfg(feature = "extensions-full")]
123mod extension;
124
125pub mod types;
126#[cfg(feature = "vtab")]
128pub mod vtab;
129
130#[cfg(feature = "vscalar")]
132pub mod vscalar;
133
134#[cfg(test)]
135mod test_all_types;
136
137pub(crate) mod util;
138
139const STATEMENT_CACHE_DEFAULT_CAPACITY: usize = 16;
141
142#[macro_export]
164macro_rules! params {
165 () => {
166 &[] as &[&dyn $crate::ToSql]
167 };
168 ($($param:expr),+ $(,)?) => {
169 &[$(&$param as &dyn $crate::ToSql),+] as &[&dyn $crate::ToSql]
170 };
171}
172
173pub type Result<T, E = Error> = result::Result<T, E>;
175
176pub trait OptionalExt<T> {
178 fn optional(self) -> Result<Option<T>>;
184}
185
186impl<T> OptionalExt<T> for Result<T> {
187 fn optional(self) -> Result<Option<T>> {
188 match self {
189 Ok(value) => Ok(Some(value)),
190 Err(Error::QueryReturnedNoRows) => Ok(None),
191 Err(e) => Err(e),
192 }
193 }
194}
195
196#[derive(Copy, Clone, Debug)]
198pub enum DatabaseName<'a> {
199 Main,
201
202 Temp,
204
205 Attached(&'a str),
207}
208
209#[allow(clippy::needless_lifetimes)]
210impl<'a> fmt::Display for DatabaseName<'a> {
211 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
212 match *self {
213 DatabaseName::Main => write!(f, "main"),
214 DatabaseName::Temp => write!(f, "temp"),
215 DatabaseName::Attached(s) => write!(f, "{s}"),
216 }
217 }
218}
219
220pub const MAIN_DB: DatabaseName<'static> = DatabaseName::Main;
222
223pub const TEMP_DB: DatabaseName<'static> = DatabaseName::Temp;
225
226pub struct Connection {
228 db: RefCell<InnerConnection>,
229 cache: StatementCache,
230 path: Option<PathBuf>,
231}
232
233unsafe impl Send for Connection {}
234
235impl Connection {
236 #[inline]
257 pub fn open<P: AsRef<Path>>(path: P) -> Result<Connection> {
258 Connection::open_with_flags(path, Config::default())
259 }
260
261 #[inline]
267 pub fn open_in_memory() -> Result<Connection> {
268 Connection::open_in_memory_with_flags(Config::default())
269 }
270
271 #[inline]
280 pub unsafe fn open_from_raw(raw: ffi::duckdb_database) -> Result<Connection> {
281 InnerConnection::new(raw, false).map(|db| Connection {
282 db: RefCell::new(db),
283 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
284 path: None, })
286 }
287
288 #[inline]
295 pub fn open_with_flags<P: AsRef<Path>>(path: P, config: Config) -> Result<Connection> {
296 #[cfg(unix)]
297 fn path_to_cstring(p: &Path) -> Result<CString> {
298 use std::os::unix::ffi::OsStrExt;
299 Ok(CString::new(p.as_os_str().as_bytes())?)
300 }
301
302 #[cfg(not(unix))]
303 fn path_to_cstring(p: &Path) -> Result<CString> {
304 let s = p.to_str().ok_or_else(|| Error::InvalidPath(p.to_owned()))?;
305 Ok(CString::new(s)?)
306 }
307
308 let c_path = path_to_cstring(path.as_ref())?;
309 let config = config.with("duckdb_api", "rust").unwrap();
310 InnerConnection::open_with_flags(&c_path, config).map(|db| Connection {
311 db: RefCell::new(db),
312 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
313 path: Some(path.as_ref().to_path_buf()),
314 })
315 }
316
317 #[inline]
323 pub fn open_in_memory_with_flags(config: Config) -> Result<Connection> {
324 Connection::open_with_flags(":memory:", config)
325 }
326
327 pub fn execute_batch(&self, sql: &str) -> Result<()> {
348 self.db.borrow_mut().execute(sql)
349 }
350
351 #[inline]
387 pub fn execute<P: Params>(&self, sql: &str, params: P) -> Result<usize> {
388 self.prepare(sql).and_then(|mut stmt| stmt.execute(params))
389 }
390
391 #[inline]
393 pub fn path(&self) -> Option<&Path> {
394 self.path.as_deref()
395 }
396
397 #[inline]
425 pub fn query_row<T, P, F>(&self, sql: &str, params: P, f: F) -> Result<T>
426 where
427 P: Params,
428 F: FnOnce(&Row<'_>) -> Result<T>,
429 {
430 self.prepare(sql)?.query_row(params, f)
431 }
432
433 #[inline]
459 pub fn query_row_and_then<T, E, P, F>(&self, sql: &str, params: P, f: F) -> Result<T, E>
460 where
461 P: Params,
462 F: FnOnce(&Row<'_>) -> Result<T, E>,
463 E: convert::From<Error>,
464 {
465 self.prepare(sql)?
466 .query(params)?
467 .get_expected_row()
468 .map_err(E::from)
469 .and_then(f)
470 }
471
472 #[inline]
491 pub fn prepare(&self, sql: &str) -> Result<Statement<'_>> {
492 self.db.borrow_mut().prepare(self, sql)
493 }
494
495 pub fn appender(&self, table: &str) -> Result<Appender<'_>> {
513 self.appender_to_db(table, &DatabaseName::Main.to_string())
514 }
515
516 pub fn appender_to_db(&self, table: &str, schema: &str) -> Result<Appender<'_>> {
533 self.db.borrow_mut().appender(self, table, schema)
534 }
535
536 #[inline]
546 #[allow(clippy::result_large_err)]
547 pub fn close(self) -> Result<(), (Connection, Error)> {
548 let r = self.db.borrow_mut().close();
549 r.map_err(move |err| (self, err))
550 }
551
552 #[inline]
555 pub fn is_autocommit(&self) -> bool {
556 self.db.borrow().is_autocommit()
557 }
558
559 pub fn try_clone(&self) -> Result<Self> {
561 let inner = self.db.borrow().try_clone()?;
562 Ok(Connection {
563 db: RefCell::new(inner),
564 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
565 path: self.path.clone(),
566 })
567 }
568
569 pub fn version(&self) -> Result<String> {
571 self.query_row("PRAGMA version", [], |row| row.get(0))
572 }
573}
574
575impl fmt::Debug for Connection {
576 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
577 f.debug_struct("Connection").field("path", &self.path).finish()
578 }
579}
580
581#[cfg(doctest)]
582doc_comment::doctest!("../../../README.md");
583
584#[cfg(test)]
585mod test {
586 use crate::types::Value;
587
588 use super::*;
589 use std::{error::Error as StdError, fmt};
590
591 use arrow::{array::Int32Array, datatypes::DataType, record_batch::RecordBatch};
592 use fallible_iterator::FallibleIterator;
593
594 #[allow(dead_code, unconditional_recursion, clippy::extra_unused_type_parameters)]
598 fn ensure_send<T: Send>() {
599 ensure_send::<Connection>();
600 }
601
602 pub fn checked_memory_handle() -> Connection {
603 Connection::open_in_memory().unwrap()
604 }
605
606 #[test]
607 fn test_params_of_vary_types() -> Result<()> {
608 let db = checked_memory_handle();
609 let sql = "BEGIN;
610 CREATE TABLE foo(bar TEXT, qux INTEGER);
611 INSERT INTO foo VALUES ('baz', 1), ('baz', 2), ('baz', 3);
612 END;";
613 db.execute_batch(sql)?;
614
615 let changed = db.execute("UPDATE foo SET qux = ? WHERE bar = ?", params![1i32, &"baz"])?;
616 assert_eq!(changed, 3);
617 Ok(())
618 }
619
620 #[test]
621 #[cfg_attr(windows, ignore = "Windows doesn't allow concurrent writes to a file")]
622 fn test_concurrent_transactions_busy_commit() -> Result<()> {
623 let tmp = tempfile::tempdir().unwrap();
624 let path = tmp.path().join("transactions.db3");
625
626 Connection::open(&path)?.execute_batch(
627 "
628 BEGIN;
629 CREATE TABLE foo(x INTEGER);
630 INSERT INTO foo VALUES(42);
631 END;",
632 )?;
633
634 let mut db1 =
635 Connection::open_with_flags(&path, Config::default().access_mode(config::AccessMode::ReadWrite)?)?;
636 let mut db2 =
637 Connection::open_with_flags(&path, Config::default().access_mode(config::AccessMode::ReadWrite)?)?;
638
639 {
640 let tx1 = db1.transaction()?;
641 let tx2 = db2.transaction()?;
642
643 tx1.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))?;
645 tx2.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))?;
646
647 tx1.execute("INSERT INTO foo VALUES(?1)", [1])?;
648 let _ = tx2.execute("INSERT INTO foo VALUES(?1)", [2]);
649
650 let _ = tx1.commit();
651 let _ = tx2.commit();
652 }
653
654 let _ = db1.transaction().expect("commit should have closed transaction");
655 let _ = db2.transaction().expect("commit should have closed transaction");
656 Ok(())
657 }
658
659 #[test]
660 fn test_persistence() -> Result<()> {
661 let temp_dir = tempfile::tempdir().unwrap();
662 let path = temp_dir.path().join("test.db3");
663
664 {
665 let db = Connection::open(&path)?;
666 let sql = "BEGIN;
667 CREATE TABLE foo(x INTEGER);
668 INSERT INTO foo VALUES(42);
669 END;";
670 db.execute_batch(sql)?;
671 }
672
673 let path_string = path.to_str().unwrap();
674 let db = Connection::open(path_string)?;
675 let the_answer: Result<i64> = db.query_row("SELECT x FROM foo", [], |r| r.get(0));
676
677 assert_eq!(42i64, the_answer?);
678 Ok(())
679 }
680
681 #[test]
682 fn test_open() {
683 let con = Connection::open_in_memory();
684 if con.is_err() {
685 panic!("open error {}", con.unwrap_err());
686 }
687 assert!(Connection::open_in_memory().is_ok());
688 let db = checked_memory_handle();
689 assert!(db.close().is_ok());
690 let _ = checked_memory_handle();
691 let _ = checked_memory_handle();
692 }
693
694 #[test]
695 fn test_open_from_raw() {
696 let con = Connection::open_in_memory();
697 assert!(con.is_ok());
698 let inner_con: InnerConnection = con.unwrap().db.into_inner();
699 unsafe {
700 assert!(Connection::open_from_raw(inner_con.db).is_ok());
701 }
702 }
703
704 #[test]
705 fn test_open_failure() -> Result<()> {
706 let filename = "no_such_file.db";
707 let result =
708 Connection::open_with_flags(filename, Config::default().access_mode(config::AccessMode::ReadOnly)?);
709 assert!(result.is_err());
710 let err = result.err().unwrap();
711 if let Error::DuckDBFailure(_e, Some(msg)) = err {
712 assert!(
715 msg.contains(filename),
716 "error message '{msg}' does not contain '{filename}'"
717 );
718 } else {
719 panic!("DuckDBFailure expected");
720 }
721 Ok(())
722 }
723
724 #[cfg(unix)]
725 #[test]
726 fn test_invalid_unicode_file_names() -> Result<()> {
727 use std::{ffi::OsStr, fs::File, os::unix::ffi::OsStrExt};
728 let temp_dir = tempfile::tempdir().unwrap();
729
730 let path = temp_dir.path();
731 if File::create(path.join(OsStr::from_bytes(&[0xFE]))).is_err() {
732 return Ok(());
734 }
735 let db_path = path.join(OsStr::from_bytes(&[0xFF]));
736 {
737 let db = Connection::open(&db_path)?;
738 let sql = "BEGIN;
739 CREATE TABLE foo(x INTEGER);
740 INSERT INTO foo VALUES(42);
741 END;";
742 db.execute_batch(sql)?;
743 }
744
745 let db = Connection::open(&db_path)?;
746 let the_answer: Result<i64> = db.query_row("SELECT x FROM foo", [], |r| r.get(0));
747
748 assert_eq!(42i64, the_answer?);
749 Ok(())
750 }
751
752 #[test]
753 fn test_close_always_ok() -> Result<()> {
754 let db = checked_memory_handle();
755
756 db.close().unwrap();
759 Ok(())
760 }
761
762 #[test]
763 fn test_execute_batch() -> Result<()> {
764 let db = checked_memory_handle();
765 let sql = "BEGIN;
766 CREATE TABLE foo(x INTEGER);
767 INSERT INTO foo VALUES(1);
768 INSERT INTO foo VALUES(2);
769 INSERT INTO foo VALUES(3);
770 INSERT INTO foo VALUES(4);
771 END;";
772 db.execute_batch(sql)?;
773
774 db.execute_batch("UPDATE foo SET x = 3 WHERE x < 3")?;
775
776 assert!(db.execute_batch("INVALID SQL").is_err());
777 Ok(())
778 }
779
780 #[test]
781 fn test_execute_single() -> Result<()> {
782 let db = checked_memory_handle();
783 db.execute_batch("CREATE TABLE foo(x INTEGER)")?;
784
785 assert_eq!(
786 3,
787 db.execute("INSERT INTO foo(x) VALUES (?), (?), (?)", [1i32, 2i32, 3i32])?
788 );
789 assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?)", [4i32])?);
790
791 assert_eq!(
792 10i32,
793 db.query_row::<i32, _, _>("SELECT SUM(x) FROM foo", [], |r| r.get(0))?
794 );
795 Ok(())
796 }
797
798 #[test]
799 fn test_prepare_column_names() -> Result<()> {
800 let db = checked_memory_handle();
801 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
802
803 let mut stmt = db.prepare("SELECT * FROM foo")?;
804 stmt.execute([])?;
805 assert_eq!(stmt.column_count(), 1);
806 assert_eq!(stmt.column_names(), vec!["x"]);
807
808 let mut stmt = db.prepare("SELECT x AS a, x AS b FROM foo")?;
809 stmt.execute([])?;
810 assert_eq!(stmt.column_count(), 2);
811 assert_eq!(stmt.column_names(), vec!["a", "b"]);
812 Ok(())
813 }
814
815 #[test]
816 fn test_prepare_execute() -> Result<()> {
817 let db = checked_memory_handle();
818 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
819
820 let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?)")?;
821 assert_eq!(insert_stmt.execute([1i32])?, 1);
822 assert_eq!(insert_stmt.execute([2i32])?, 1);
823 assert_eq!(insert_stmt.execute([3i32])?, 1);
824
825 assert!(insert_stmt.execute(["hello"]).is_err());
826 let mut update_stmt = db.prepare("UPDATE foo SET x=? WHERE x<?")?;
831 assert_eq!(update_stmt.execute([3i32, 3i32])?, 2);
832 assert_eq!(update_stmt.execute([3i32, 3i32])?, 0);
833 assert_eq!(update_stmt.execute([8i32, 8i32])?, 3);
834 Ok(())
835 }
836
837 #[test]
838 fn test_prepare_query() -> Result<()> {
839 let db = checked_memory_handle();
840 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
841
842 let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?)")?;
843 assert_eq!(insert_stmt.execute([1i32])?, 1);
844 assert_eq!(insert_stmt.execute([2i32])?, 1);
845 assert_eq!(insert_stmt.execute([3i32])?, 1);
846
847 let mut query = db.prepare("SELECT x FROM foo WHERE x < ? ORDER BY x DESC")?;
848 {
849 let mut rows = query.query([4i32])?;
850 let mut v = Vec::<i32>::new();
851
852 while let Some(row) = rows.next()? {
853 v.push(row.get(0)?);
854 }
855
856 assert_eq!(v, [3i32, 2, 1]);
857 }
858
859 {
860 let mut rows = query.query([3i32])?;
861 let mut v = Vec::<i32>::new();
862
863 while let Some(row) = rows.next()? {
864 v.push(row.get(0)?);
865 }
866
867 assert_eq!(v, [2i32, 1]);
868 }
869 Ok(())
870 }
871
872 #[test]
873 fn test_query_map() -> Result<()> {
874 let db = checked_memory_handle();
875 let sql = "BEGIN;
876 CREATE TABLE foo(x INTEGER, y TEXT);
877 INSERT INTO foo VALUES(4, 'hello');
878 INSERT INTO foo VALUES(3, ', ');
879 INSERT INTO foo VALUES(2, 'world');
880 INSERT INTO foo VALUES(1, '!');
881 END;";
882 db.execute_batch(sql)?;
883
884 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
885 let results: Result<Vec<String>> = query.query([])?.map(|row| row.get(1)).collect();
886
887 assert_eq!(results?.concat(), "hello, world!");
888 Ok(())
889 }
890
891 #[test]
892 fn test_query_row() -> Result<()> {
893 let db = checked_memory_handle();
894 let sql = "BEGIN;
895 CREATE TABLE foo(x INTEGER);
896 INSERT INTO foo VALUES(1);
897 INSERT INTO foo VALUES(2);
898 INSERT INTO foo VALUES(3);
899 INSERT INTO foo VALUES(4);
900 END;";
901 db.execute_batch(sql)?;
902
903 assert_eq!(
904 10i64,
905 db.query_row::<i64, _, _>("SELECT SUM(x) FROM foo", [], |r| r.get(0))?
906 );
907
908 let result: Result<i64> = db.query_row("SELECT x FROM foo WHERE x > 5", [], |r| r.get(0));
909 match result.unwrap_err() {
910 Error::QueryReturnedNoRows => (),
911 err => panic!("Unexpected error {err}"),
912 }
913
914 let bad_query_result = db.query_row("NOT A PROPER QUERY; test123", [], |_| Ok(()));
915
916 assert!(bad_query_result.is_err());
917 Ok(())
918 }
919
920 #[test]
921 fn test_optional() -> Result<()> {
922 let db = checked_memory_handle();
923
924 let result: Result<i64> = db.query_row("SELECT 1 WHERE 0 <> 0", [], |r| r.get(0));
925 let result = result.optional();
926 match result? {
927 None => (),
928 _ => panic!("Unexpected result"),
929 }
930
931 let result: Result<i64> = db.query_row("SELECT 1 WHERE 0 == 0", [], |r| r.get(0));
932 let result = result.optional();
933 match result? {
934 Some(1) => (),
935 _ => panic!("Unexpected result"),
936 }
937
938 let bad_query_result: Result<i64> = db.query_row("NOT A PROPER QUERY", [], |r| r.get(0));
939 let bad_query_result = bad_query_result.optional();
940 assert!(bad_query_result.is_err());
941 Ok(())
942 }
943
944 #[test]
945 fn test_prepare_failures() -> Result<()> {
946 let db = checked_memory_handle();
947 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
948
949 let _ = db.prepare("SELECT * FROM does_not_exist").unwrap_err();
950 Ok(())
952 }
953
954 #[test]
955 fn test_is_autocommit() {
956 let db = checked_memory_handle();
957 assert!(db.is_autocommit(), "autocommit expected to be active by default");
958 }
959
960 #[test]
961 #[ignore = "not supported"]
962 fn test_statement_debugging() -> Result<()> {
963 let db = checked_memory_handle();
964 let query = "SELECT 12345";
965 let stmt = db.prepare(query)?;
966
967 assert!(format!("{stmt:?}").contains(query));
968 Ok(())
969 }
970
971 #[test]
972 fn test_notnull_constraint_error() -> Result<()> {
973 let db = checked_memory_handle();
974 db.execute_batch("CREATE TABLE foo(x TEXT NOT NULL)")?;
975
976 let result = db.execute("INSERT INTO foo (x) VALUES (NULL)", []);
977 assert!(result.is_err());
978
979 match result.unwrap_err() {
980 Error::DuckDBFailure(err, _) => {
981 assert_eq!(err.code, ErrorCode::Unknown);
983 }
984 err => panic!("Unexpected error {err}"),
985 }
986 Ok(())
987 }
988
989 #[test]
990 fn test_clone() -> Result<()> {
991 {
993 let owned_con = checked_memory_handle();
994 {
995 let cloned_con = owned_con.try_clone().unwrap();
996 cloned_con.execute_batch("create table test (c1 bigint)")?;
997 cloned_con.close().unwrap();
998 }
999 owned_con.execute_batch("create table test2 (c1 bigint)")?;
1000 owned_con.close().unwrap();
1001 }
1002
1003 {
1005 let cloned_con = {
1006 let owned_con = checked_memory_handle();
1007 let clone = owned_con.try_clone().unwrap();
1008 owned_con.execute_batch("create table test (c1 bigint)")?;
1009 owned_con.close().unwrap();
1010 clone
1011 };
1012 cloned_con.execute_batch("create table test2 (c1 bigint)")?;
1013 cloned_con.close().unwrap();
1014 }
1015 Ok(())
1016 }
1017
1018 mod query_and_then_tests {
1019 use super::*;
1020
1021 #[derive(Debug)]
1022 enum CustomError {
1023 SomeError,
1024 Sqlite(Error),
1025 }
1026
1027 impl fmt::Display for CustomError {
1028 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1029 match *self {
1030 CustomError::SomeError => write!(f, "my custom error"),
1031 CustomError::Sqlite(ref se) => write!(f, "my custom error: {se}"),
1032 }
1033 }
1034 }
1035
1036 impl StdError for CustomError {
1037 fn description(&self) -> &str {
1038 "my custom error"
1039 }
1040
1041 fn cause(&self) -> Option<&dyn StdError> {
1042 match *self {
1043 CustomError::SomeError => None,
1044 CustomError::Sqlite(ref se) => Some(se),
1045 }
1046 }
1047 }
1048
1049 impl From<Error> for CustomError {
1050 fn from(se: Error) -> CustomError {
1051 CustomError::Sqlite(se)
1052 }
1053 }
1054
1055 type CustomResult<T> = Result<T, CustomError>;
1056
1057 #[test]
1058 fn test_query_and_then() -> Result<()> {
1059 let db = checked_memory_handle();
1060 let sql = "BEGIN;
1061 CREATE TABLE foo(x INTEGER, y TEXT);
1062 INSERT INTO foo VALUES(4, 'hello');
1063 INSERT INTO foo VALUES(3, ', ');
1064 INSERT INTO foo VALUES(2, 'world');
1065 INSERT INTO foo VALUES(1, '!');
1066 END;";
1067 db.execute_batch(sql)?;
1068
1069 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1070 let results: Result<Vec<String>> = query.query_and_then([], |row| row.get(1))?.collect();
1071
1072 assert_eq!(results?.concat(), "hello, world!");
1073 Ok(())
1074 }
1075
1076 #[test]
1077 fn test_query_and_then_fails() -> Result<()> {
1078 let db = checked_memory_handle();
1079 let sql = "BEGIN;
1080 CREATE TABLE foo(x INTEGER, y TEXT);
1081 INSERT INTO foo VALUES(4, 'hello');
1082 INSERT INTO foo VALUES(3, ', ');
1083 INSERT INTO foo VALUES(2, 'world');
1084 INSERT INTO foo VALUES(1, '!');
1085 END;";
1086 db.execute_batch(sql)?;
1087
1088 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1089 let bad_type: Result<Vec<f64>> = query.query_and_then([], |row| row.get(1))?.collect();
1090
1091 match bad_type.unwrap_err() {
1092 Error::InvalidColumnType(..) => (),
1093 err => panic!("Unexpected error {err}"),
1094 }
1095
1096 let bad_idx: Result<Vec<String>> = query.query_and_then([], |row| row.get(3))?.collect();
1097
1098 match bad_idx.unwrap_err() {
1099 Error::InvalidColumnIndex(_) => (),
1100 err => panic!("Unexpected error {err}"),
1101 }
1102 Ok(())
1103 }
1104
1105 #[test]
1106 fn test_query_and_then_custom_error() -> CustomResult<()> {
1107 let db = checked_memory_handle();
1108 let sql = "BEGIN;
1109 CREATE TABLE foo(x INTEGER, y TEXT);
1110 INSERT INTO foo VALUES(4, 'hello');
1111 INSERT INTO foo VALUES(3, ', ');
1112 INSERT INTO foo VALUES(2, 'world');
1113 INSERT INTO foo VALUES(1, '!');
1114 END;";
1115 db.execute_batch(sql)?;
1116
1117 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1118 let results: CustomResult<Vec<String>> = query
1119 .query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite))?
1120 .collect();
1121
1122 assert_eq!(results?.concat(), "hello, world!");
1123 Ok(())
1124 }
1125
1126 #[test]
1127 fn test_query_and_then_custom_error_fails() -> Result<()> {
1128 let db = checked_memory_handle();
1129 let sql = "BEGIN;
1130 CREATE TABLE foo(x INTEGER, y TEXT);
1131 INSERT INTO foo VALUES(4, 'hello');
1132 INSERT INTO foo VALUES(3, ', ');
1133 INSERT INTO foo VALUES(2, 'world');
1134 INSERT INTO foo VALUES(1, '!');
1135 END;";
1136 db.execute_batch(sql)?;
1137
1138 let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
1139 let bad_type: CustomResult<Vec<f64>> = query
1140 .query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite))?
1141 .collect();
1142
1143 match bad_type.unwrap_err() {
1144 CustomError::Sqlite(Error::InvalidColumnType(..)) => (),
1145 err => panic!("Unexpected error {err}"),
1146 }
1147
1148 let bad_idx: CustomResult<Vec<String>> = query
1149 .query_and_then([], |row| row.get(3).map_err(CustomError::Sqlite))?
1150 .collect();
1151
1152 match bad_idx.unwrap_err() {
1153 CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
1154 err => panic!("Unexpected error {err}"),
1155 }
1156
1157 let non_sqlite_err: CustomResult<Vec<String>> =
1158 query.query_and_then([], |_| Err(CustomError::SomeError))?.collect();
1159
1160 match non_sqlite_err.unwrap_err() {
1161 CustomError::SomeError => (),
1162 err => panic!("Unexpected error {err}"),
1163 }
1164 Ok(())
1165 }
1166
1167 #[test]
1168 fn test_query_row_and_then_custom_error() -> CustomResult<()> {
1169 let db = checked_memory_handle();
1170 let sql = "BEGIN;
1171 CREATE TABLE foo(x INTEGER, y TEXT);
1172 INSERT INTO foo VALUES(4, 'hello');
1173 END;";
1174 db.execute_batch(sql)?;
1175
1176 let query = "SELECT x, y FROM foo ORDER BY x DESC";
1177 let results: CustomResult<String> =
1178 db.query_row_and_then(query, [], |row| row.get(1).map_err(CustomError::Sqlite));
1179
1180 assert_eq!(results?, "hello");
1181 Ok(())
1182 }
1183
1184 #[test]
1185 fn test_query_row_and_then_custom_error_fails() -> Result<()> {
1186 let db = checked_memory_handle();
1187 let sql = "BEGIN;
1188 CREATE TABLE foo(x INTEGER, y TEXT);
1189 INSERT INTO foo VALUES(4, 'hello');
1190 END;";
1191 db.execute_batch(sql)?;
1192
1193 let query = "SELECT x, y FROM foo ORDER BY x DESC";
1194 let bad_type: CustomResult<f64> =
1195 db.query_row_and_then(query, [], |row| row.get(1).map_err(CustomError::Sqlite));
1196
1197 match bad_type.unwrap_err() {
1198 CustomError::Sqlite(Error::InvalidColumnType(..)) => (),
1199 err => panic!("Unexpected error {err}"),
1200 }
1201
1202 let bad_idx: CustomResult<String> =
1203 db.query_row_and_then(query, [], |row| row.get(3).map_err(CustomError::Sqlite));
1204
1205 match bad_idx.unwrap_err() {
1206 CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
1207 err => panic!("Unexpected error {err}"),
1208 }
1209
1210 let non_sqlite_err: CustomResult<String> =
1211 db.query_row_and_then(query, [], |_| Err(CustomError::SomeError));
1212
1213 match non_sqlite_err.unwrap_err() {
1214 CustomError::SomeError => (),
1215 err => panic!("Unexpected error {err}"),
1216 }
1217 Ok(())
1218 }
1219 }
1220
1221 #[test]
1222 fn test_dynamic() -> Result<()> {
1223 let db = checked_memory_handle();
1224 let sql = "BEGIN;
1225 CREATE TABLE foo(x INTEGER, y TEXT);
1226 INSERT INTO foo VALUES(4, 'hello');
1227 END;";
1228 db.execute_batch(sql)?;
1229
1230 db.query_row("SELECT * FROM foo", [], |r| {
1231 assert_eq!(2, r.as_ref().column_count());
1232 Ok(())
1233 })
1234 }
1235 #[test]
1236 fn test_dyn_box() -> Result<()> {
1237 let db = checked_memory_handle();
1238 db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
1239 let b: Box<dyn ToSql> = Box::new(5);
1240 db.execute("INSERT INTO foo VALUES(?)", [b])?;
1241 db.query_row("SELECT x FROM foo", [], |r| {
1242 assert_eq!(5, r.get_unwrap::<_, i32>(0));
1243 Ok(())
1244 })
1245 }
1246
1247 #[test]
1248 fn test_alter_table() -> Result<()> {
1249 let db = checked_memory_handle();
1250 db.execute_batch("CREATE TABLE x(t INTEGER);")?;
1251 db.execute("ALTER TABLE x RENAME TO y;", [])?;
1253 Ok(())
1254 }
1255
1256 #[test]
1257 fn test_query_arrow_record_batch_small() -> Result<()> {
1258 let db = checked_memory_handle();
1259 let sql = "BEGIN TRANSACTION;
1260 CREATE TABLE test(t INTEGER);
1261 INSERT INTO test VALUES (1); INSERT INTO test VALUES (2); INSERT INTO test VALUES (3); INSERT INTO test VALUES (4); INSERT INTO test VALUES (5);
1262 END TRANSACTION;";
1263 db.execute_batch(sql)?;
1264 let mut stmt = db.prepare("select t from test order by t desc")?;
1265 let mut arr = stmt.query_arrow([])?;
1266
1267 let schema = arr.get_schema();
1268 assert_eq!(schema.fields().len(), 1);
1269 assert_eq!(schema.field(0).name(), "t");
1270 assert_eq!(schema.field(0).data_type(), &DataType::Int32);
1271
1272 let rb = arr.next().unwrap();
1273 let column = rb.column(0).as_any().downcast_ref::<Int32Array>().unwrap();
1274 assert_eq!(column.len(), 5);
1275 assert_eq!(column.value(0), 5);
1276 assert_eq!(column.value(1), 4);
1277 assert_eq!(column.value(2), 3);
1278 assert_eq!(column.value(3), 2);
1279 assert_eq!(column.value(4), 1);
1280
1281 assert!(arr.next().is_none());
1282 Ok(())
1283 }
1284
1285 #[test]
1286 fn test_query_arrow_record_batch_large() -> Result<()> {
1287 let db = checked_memory_handle();
1288 db.execute_batch("BEGIN TRANSACTION")?;
1289 db.execute_batch("CREATE TABLE test(t INTEGER);")?;
1290 for _ in 0..600 {
1291 db.execute_batch("INSERT INTO test VALUES (1); INSERT INTO test VALUES (2); INSERT INTO test VALUES (3); INSERT INTO test VALUES (4); INSERT INTO test VALUES (5);")?;
1292 }
1293 db.execute_batch("END TRANSACTION")?;
1294 let rbs: Vec<RecordBatch> = db.prepare("select t from test order by t")?.query_arrow([])?.collect();
1295 assert_eq!(rbs.iter().map(|rb| rb.num_rows()).sum::<usize>(), 3000);
1298 assert_eq!(
1299 rbs.iter()
1300 .map(|rb| rb
1301 .column(0)
1302 .as_any()
1303 .downcast_ref::<Int32Array>()
1304 .unwrap()
1305 .iter()
1306 .map(|i| i.unwrap())
1307 .sum::<i32>())
1308 .sum::<i32>(),
1309 9000
1310 );
1311 Ok(())
1312 }
1313
1314 #[test]
1315 fn round_trip_interval() -> Result<()> {
1316 let db = checked_memory_handle();
1317 db.execute_batch("CREATE TABLE foo (t INTERVAL);")?;
1318
1319 let d = Value::Interval {
1320 months: 1,
1321 days: 2,
1322 nanos: 3,
1323 };
1324 db.execute("INSERT INTO foo VALUES (?)", [d])?;
1325
1326 let mut stmt = db.prepare("SELECT t FROM foo")?;
1327 let mut rows = stmt.query([])?;
1328 let row = rows.next()?.unwrap();
1329 let d: Value = row.get_unwrap(0);
1330 assert_eq!(d, d);
1331 Ok(())
1332 }
1333
1334 #[test]
1335 fn test_database_name_to_string() -> Result<()> {
1336 assert_eq!(DatabaseName::Main.to_string(), "main");
1337 assert_eq!(DatabaseName::Temp.to_string(), "temp");
1338 assert_eq!(DatabaseName::Attached("abc").to_string(), "abc");
1339 Ok(())
1340 }
1341
1342 #[cfg(feature = "bundled")]
1343 #[test]
1344 fn test_version() -> Result<()> {
1345 let db = checked_memory_handle();
1346 let expected: String = format!("v{}", env!("CARGO_PKG_VERSION"));
1347 let actual = db.version()?;
1348 assert_eq!(expected, actual);
1349 Ok(())
1350 }
1351}