1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
use crate::check;
use crate::database::DatabaseOwnership::{Borrowed, Owned};
use crate::duckly::{
duckdb_close, duckdb_connect, duckdb_connection, duckdb_database, duckdb_open,
};
use crate::Connection;
use std::error::Error;
use std::ffi::{c_void, CString};
use std::ptr::{addr_of, null_mut};
#[repr(C)]
#[derive(Debug)]
struct Wrapper {
instance: *const c_void,
}
#[derive(Debug)]
enum DatabaseOwnership {
Owned(duckdb_database),
Borrowed(Wrapper),
}
#[derive(Debug)]
pub struct Database(DatabaseOwnership);
impl Database {
pub fn new() -> Result<Self, Box<dyn Error>> {
let mut db: duckdb_database = null_mut();
let filename = CString::new(":memory:").unwrap();
unsafe {
check!(duckdb_open(filename.as_ptr(), &mut db));
}
Ok(Self(Owned(db)))
}
pub fn from_cpp_duckdb(ptr: *mut c_void) -> Self {
Self(Borrowed(Wrapper { instance: ptr }))
}
pub fn connect(&self) -> Result<Connection, Box<dyn Error>> {
let mut connection: duckdb_connection = null_mut();
let db = match &self.0 {
Borrowed(wrapper) => addr_of!(wrapper) as duckdb_database,
Owned(ptr) => *ptr,
};
unsafe {
check!(duckdb_connect(db, &mut connection));
}
Ok(Connection::from(connection))
}
}
impl Drop for Database {
fn drop(&mut self) {
if let Owned(mut ptr) = self.0 {
unsafe { duckdb_close(&mut ptr) }
}
}
}
#[cfg(test)]
mod test {
use crate::database::Database;
use crate::Connection;
use std::any::{Any, TypeId};
use std::error::Error;
#[test]
fn test_database_creation() -> Result<(), Box<dyn Error>> {
let db = Database::new()?;
let conn = db.connect()?;
drop(db);
assert_eq!(conn.type_id(), TypeId::of::<Connection>());
drop(conn);
Ok(())
}
}