duckdb/
lib.rs

1//! duckdb-rs is an ergonomic wrapper for using DuckDB from Rust. It attempts to
2//! expose an interface similar to [rusqlite](https://github.com/rusqlite/rusqlite).
3//!
4//! ```rust
5//! use duckdb::{params, Connection, Result};
6//! use duckdb::arrow::record_batch::RecordBatch;
7//! use duckdb::arrow::util::pretty::print_batches;
8//!
9//! #[derive(Debug)]
10//! struct Person {
11//!     id: i32,
12//!     name: String,
13//!     data: Option<Vec<u8>>,
14//! }
15//!
16//! fn main() -> Result<()> {
17//!     let conn = Connection::open_in_memory()?;
18//!
19//!     conn.execute_batch(
20//!         r"CREATE SEQUENCE seq;
21//!           CREATE TABLE person (
22//!                   id              INTEGER PRIMARY KEY DEFAULT NEXTVAL('seq'),
23//!                   name            TEXT NOT NULL,
24//!                   data            BLOB
25//!                   );
26//!          ")?;
27//!     let me = Person {
28//!         id: 0,
29//!         name: "Steven".to_string(),
30//!         data: None,
31//!     };
32//!     conn.execute(
33//!         "INSERT INTO person (name, data) VALUES (?, ?)",
34//!         params![me.name, me.data],
35//!     )?;
36//!
37//!     let mut stmt = conn.prepare("SELECT id, name, data FROM person")?;
38//!     let person_iter = stmt.query_map([], |row| {
39//!         Ok(Person {
40//!             id: row.get(0)?,
41//!             name: row.get(1)?,
42//!             data: row.get(2)?,
43//!         })
44//!     })?;
45//!
46//!     for person in person_iter {
47//!         println!("Found person {:?}", person.unwrap());
48//!     }
49//!
50//!     // query table by arrow
51//!     let rbs: Vec<RecordBatch> = stmt.query_arrow([])?.collect();
52//!     print_batches(&rbs);
53//!     Ok(())
54//! }
55//! ```
56#![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
91// re-export dependencies to minimise version maintenance for crate users
92pub use arrow;
93#[cfg(feature = "polars")]
94pub use polars;
95#[cfg(feature = "polars")]
96pub use polars_arrow as arrow2;
97
98/// The core module contains the main functionality of the DuckDB crate.
99pub 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/// The duckdb table function interface
127#[cfg(feature = "vtab")]
128pub mod vtab;
129
130/// The duckdb scalar function interface
131#[cfg(feature = "vscalar")]
132pub mod vscalar;
133
134#[cfg(test)]
135mod test_all_types;
136
137pub(crate) mod util;
138
139// Number of cached prepared statements we'll hold on to.
140const STATEMENT_CACHE_DEFAULT_CAPACITY: usize = 16;
141
142/// A macro making it more convenient to pass heterogeneous or long lists of
143/// parameters as a `&[&dyn ToSql]`.
144///
145/// # Example
146///
147/// ```rust,no_run
148/// # use duckdb::{Result, Connection, params};
149///
150/// struct Person {
151///     name: String,
152///     age_in_years: u8,
153///     data: Option<Vec<u8>>,
154/// }
155///
156/// fn add_person(conn: &Connection, person: &Person) -> Result<()> {
157///     conn.execute("INSERT INTO person (name, age_in_years, data)
158///                   VALUES (?1, ?2, ?3)",
159///                  params![person.name, person.age_in_years, person.data])?;
160///     Ok(())
161/// }
162/// ```
163#[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
173/// A typedef of the result returned by many methods.
174pub type Result<T, E = Error> = result::Result<T, E>;
175
176/// See the [method documentation](#tymethod.optional).
177pub trait OptionalExt<T> {
178    /// Converts a `Result<T>` into a `Result<Option<T>>`.
179    ///
180    /// By default, duckdb-rs treats 0 rows being returned from a query that is
181    /// expected to return 1 row as an error. This method will
182    /// handle that error, and give you back an `Option<T>` instead.
183    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/// Name for a database within a DuckDB connection.
197#[derive(Copy, Clone, Debug)]
198pub enum DatabaseName<'a> {
199    /// The main database.
200    Main,
201
202    /// The temporary database (e.g., any "CREATE TEMPORARY TABLE" tables).
203    Temp,
204
205    /// A database that has been attached via "ATTACH DATABASE ...".
206    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
220/// Shorthand for [`DatabaseName::Main`].
221pub const MAIN_DB: DatabaseName<'static> = DatabaseName::Main;
222
223/// Shorthand for [`DatabaseName::Temp`].
224pub const TEMP_DB: DatabaseName<'static> = DatabaseName::Temp;
225
226/// A connection to a DuckDB database.
227pub struct Connection {
228    db: RefCell<InnerConnection>,
229    cache: StatementCache,
230    path: Option<PathBuf>,
231}
232
233unsafe impl Send for Connection {}
234
235impl Connection {
236    /// Open a new connection to a DuckDB database.
237    ///
238    /// `Connection::open(path)` is equivalent to
239    /// `Connection::open_with_flags(path,
240    /// Config::default())`.
241    ///
242    /// ```rust,no_run
243    /// # use duckdb::{Connection, Result};
244    /// fn open_my_db() -> Result<()> {
245    ///     let path = "./my_db.db3";
246    ///     let db = Connection::open(&path)?;
247    ///     println!("{}", db.is_autocommit());
248    ///     Ok(())
249    /// }
250    /// ```
251    ///
252    /// # Failure
253    ///
254    /// Will return `Err` if `path` cannot be converted to a C-compatible
255    /// string or if the underlying DuckDB open call fails.
256    #[inline]
257    pub fn open<P: AsRef<Path>>(path: P) -> Result<Connection> {
258        Connection::open_with_flags(path, Config::default())
259    }
260
261    /// Open a new connection to an in-memory DuckDB database.
262    ///
263    /// # Failure
264    ///
265    /// Will return `Err` if the underlying DuckDB open call fails.
266    #[inline]
267    pub fn open_in_memory() -> Result<Connection> {
268        Connection::open_in_memory_with_flags(Config::default())
269    }
270
271    /// Open a new connection to an ffi database.
272    ///
273    /// # Failure
274    ///
275    /// Will return `Err` if the underlying DuckDB open call fails.
276    /// # Safety
277    ///
278    /// Need to pass in a valid db instance
279    #[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, // Can we know the path from connection?
285        })
286    }
287
288    /// Open a new connection to a DuckDB database.
289    ///
290    /// # Failure
291    ///
292    /// Will return `Err` if `path` cannot be converted to a C-compatible
293    /// string or if the underlying DuckDB open call fails.
294    #[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    /// Open a new connection to an in-memory DuckDB database.
318    ///
319    /// # Failure
320    ///
321    /// Will return `Err` if the underlying DuckDB open call fails.
322    #[inline]
323    pub fn open_in_memory_with_flags(config: Config) -> Result<Connection> {
324        Connection::open_with_flags(":memory:", config)
325    }
326
327    /// Convenience method to run multiple SQL statements (that cannot take any
328    /// parameters).
329    ///
330    /// ## Example
331    ///
332    /// ```rust,no_run
333    /// # use duckdb::{Connection, Result};
334    /// fn create_tables(conn: &Connection) -> Result<()> {
335    ///     conn.execute_batch("BEGIN;
336    ///                         CREATE TABLE foo(x INTEGER);
337    ///                         CREATE TABLE bar(y TEXT);
338    ///                         COMMIT;",
339    ///     )
340    /// }
341    /// ```
342    ///
343    /// # Failure
344    ///
345    /// Will return `Err` if `sql` cannot be converted to a C-compatible string
346    /// or if the underlying DuckDB call fails.
347    pub fn execute_batch(&self, sql: &str) -> Result<()> {
348        self.db.borrow_mut().execute(sql)
349    }
350
351    /// Convenience method to prepare and execute a single SQL statement.
352    ///
353    /// On success, returns the number of rows that were changed or inserted or
354    /// deleted.
355    ///
356    /// ## Example
357    ///
358    /// ### With params
359    ///
360    /// ```rust,no_run
361    /// # use duckdb::{Connection};
362    /// fn update_rows(conn: &Connection) {
363    ///     match conn.execute("UPDATE foo SET bar = 'baz' WHERE qux = ?", [1i32]) {
364    ///         Ok(updated) => println!("{} rows were updated", updated),
365    ///         Err(err) => println!("update failed: {}", err),
366    ///     }
367    /// }
368    /// ```
369    ///
370    /// ### With params of varying types
371    ///
372    /// ```rust,no_run
373    /// # use duckdb::{Connection, params};
374    /// fn update_rows(conn: &Connection) {
375    ///     match conn.execute("UPDATE foo SET bar = ? WHERE qux = ?", params![&"baz", 1i32]) {
376    ///         Ok(updated) => println!("{} rows were updated", updated),
377    ///         Err(err) => println!("update failed: {}", err),
378    ///     }
379    /// }
380    /// ```
381    ///
382    /// # Failure
383    ///
384    /// Will return `Err` if `sql` cannot be converted to a C-compatible string
385    /// or if the underlying DuckDB call fails.
386    #[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    /// Returns the path to the database file, if one exists and is known.
392    #[inline]
393    pub fn path(&self) -> Option<&Path> {
394        self.path.as_deref()
395    }
396
397    /// Convenience method to execute a query that is expected to return a
398    /// single row.
399    ///
400    /// ## Example
401    ///
402    /// ```rust,no_run
403    /// # use duckdb::{Result, Connection};
404    /// fn preferred_locale(conn: &Connection) -> Result<String> {
405    ///     conn.query_row(
406    ///         "SELECT value FROM preferences WHERE name='locale'",
407    ///         [],
408    ///         |row| row.get(0),
409    ///     )
410    /// }
411    /// ```
412    ///
413    /// If the query returns more than one row, all rows except the first are
414    /// ignored.
415    ///
416    /// Returns `Err(QueryReturnedNoRows)` if no results are returned. If the
417    /// query truly is optional, you can call `.optional()` on the result of
418    /// this to get a `Result<Option<T>>`.
419    ///
420    /// # Failure
421    ///
422    /// Will return `Err` if `sql` cannot be converted to a C-compatible string
423    /// or if the underlying DuckDB call fails.
424    #[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    /// Convenience method to execute a query that is expected to return a
434    /// single row, and execute a mapping via `f` on that returned row with
435    /// the possibility of failure. The `Result` type of `f` must implement
436    /// `std::convert::From<Error>`.
437    ///
438    /// ## Example
439    ///
440    /// ```rust,no_run
441    /// # use duckdb::{Result, Connection};
442    /// fn preferred_locale(conn: &Connection) -> Result<String> {
443    ///     conn.query_row_and_then(
444    ///         "SELECT value FROM preferences WHERE name='locale'",
445    ///         [],
446    ///         |row| row.get(0),
447    ///     )
448    /// }
449    /// ```
450    ///
451    /// If the query returns more than one row, all rows except the first are
452    /// ignored.
453    ///
454    /// # Failure
455    ///
456    /// Will return `Err` if `sql` cannot be converted to a C-compatible string
457    /// or if the underlying DuckDB call fails.
458    #[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    /// Prepare a SQL statement for execution.
473    ///
474    /// ## Example
475    ///
476    /// ```rust,no_run
477    /// # use duckdb::{Connection, Result};
478    /// fn insert_new_people(conn: &Connection) -> Result<()> {
479    ///     let mut stmt = conn.prepare("INSERT INTO People (name) VALUES (?)")?;
480    ///     stmt.execute(["Joe Smith"])?;
481    ///     stmt.execute(["Bob Jones"])?;
482    ///     Ok(())
483    /// }
484    /// ```
485    ///
486    /// # Failure
487    ///
488    /// Will return `Err` if `sql` cannot be converted to a C-compatible string
489    /// or if the underlying DuckDB call fails.
490    #[inline]
491    pub fn prepare(&self, sql: &str) -> Result<Statement<'_>> {
492        self.db.borrow_mut().prepare(self, sql)
493    }
494
495    /// Create an Appender for fast import data
496    /// default to use `DatabaseName::Main`
497    ///
498    /// ## Example
499    ///
500    /// ```rust,no_run
501    /// # use duckdb::{Connection, Result, params};
502    /// fn insert_rows(conn: &Connection) -> Result<()> {
503    ///     let mut app = conn.appender("foo")?;
504    ///     app.append_rows([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]])?;
505    ///     Ok(())
506    /// }
507    /// ```
508    ///
509    /// # Failure
510    ///
511    /// Will return `Err` if `table` not exists
512    pub fn appender(&self, table: &str) -> Result<Appender<'_>> {
513        self.appender_to_db(table, &DatabaseName::Main.to_string())
514    }
515
516    /// Create an Appender for fast import data
517    ///
518    /// ## Example
519    ///
520    /// ```rust,no_run
521    /// # use duckdb::{Connection, Result, params, DatabaseName};
522    /// fn insert_rows(conn: &Connection) -> Result<()> {
523    ///     let mut app = conn.appender_to_db("foo", &DatabaseName::Main.to_string())?;
524    ///     app.append_rows([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]])?;
525    ///     Ok(())
526    /// }
527    /// ```
528    ///
529    /// # Failure
530    ///
531    /// Will return `Err` if `table` not exists
532    pub fn appender_to_db(&self, table: &str, schema: &str) -> Result<Appender<'_>> {
533        self.db.borrow_mut().appender(self, table, schema)
534    }
535
536    /// Close the DuckDB connection.
537    ///
538    /// This is functionally equivalent to the `Drop` implementation for
539    /// `Connection` except that on failure, it returns an error and the
540    /// connection itself (presumably so closing can be attempted again).
541    ///
542    /// # Failure
543    ///
544    /// Will return `Err` if the underlying DuckDB call fails.
545    #[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    /// Test for auto-commit mode.
553    /// Autocommit mode is on by default.
554    #[inline]
555    pub fn is_autocommit(&self) -> bool {
556        self.db.borrow().is_autocommit()
557    }
558
559    /// Creates a new connection to the already-opened database.
560    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    /// Returns the version of the DuckDB library
570    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    // this function is never called, but is still type checked; in
595    // particular, calls with specific instantiations will require
596    // that those types are `Send`.
597    #[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            // SELECT first makes sqlite lock with a shared lock
644            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            // TODO: update error code
713            // assert_eq!(ErrorCode::CannotOpen, e.code);
714            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            // Skip test, filesystem doesn't support invalid Unicode
733            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        // TODO: prepare a query but not execute it
757
758        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        // NOTE: can't execute on errored stmt
827        // assert!(insert_stmt.execute(["goodbye"]).is_err());
828        // assert!(insert_stmt.execute([types::Null]).is_err());
829
830        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        // assert!(format!("{}", err).contains("does_not_exist"));
951        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                // TODO(wangfenjin): Update errorcode
982                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        // 1. Drop the cloned connection first. The original connection should still be able to run queries.
992        {
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        // 2. Close the original connection first. The cloned connection should still be able to run queries.
1004        {
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        // `execute_batch` should be used but `execute` should also work
1252        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        // batch size is not stable
1296        // assert_eq!(rbs.len(), 3);
1297        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}