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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(improper_ctypes)]
#[allow(clippy::all)]
mod bindings {
include!(concat!(env!("OUT_DIR"), "/bindgen.rs"));
}
pub use bindings::*;
use std::os::raw::c_uint;
pub const DuckDBError: c_uint = duckdb_state_DuckDBError;
pub const DuckDBSuccess: c_uint = duckdb_state_DuckDBSuccess;
pub use self::error::*;
mod error;
#[cfg(test)]
mod tests {
use super::*;
use std::ffi::{CStr, CString};
use std::mem;
use std::os::raw::c_char;
use std::ptr;
use std::slice;
unsafe fn print_result(mut result: duckdb_result) {
let columns = slice::from_raw_parts(result.columns, result.column_count as usize);
for i in 0..result.column_count {
print!("{} ", CStr::from_ptr(columns[i as usize].name).to_string_lossy());
}
println!();
for row_idx in 0..result.row_count {
for col_idx in 0..result.column_count {
let val = duckdb_value_varchar(&mut result, col_idx, row_idx);
print!("{} ", CStr::from_ptr(val).to_string_lossy());
}
println!();
}
}
#[test]
fn basic_api_usage() {
unsafe {
let mut db: duckdb_database = ptr::null_mut();
let mut con: duckdb_connection = ptr::null_mut();
if duckdb_open(ptr::null_mut(), &mut db) != duckdb_state_DuckDBSuccess {
panic!("duckdb_open error")
}
if duckdb_connect(db, &mut con) != duckdb_state_DuckDBSuccess {
panic!("duckdb_connect error")
}
let sql = CString::new("CREATE TABLE integers(i INTEGER, j INTEGER);").unwrap();
if duckdb_query(con, sql.as_ptr() as *const c_char, ptr::null_mut()) != duckdb_state_DuckDBSuccess {
panic!("CREATE TABLE error")
}
let sql = CString::new("INSERT INTO integers VALUES (3, 4), (5, 6), (7, NULL);").unwrap();
if duckdb_query(con, sql.as_ptr() as *const c_char, ptr::null_mut()) != duckdb_state_DuckDBSuccess {
panic!("INSERT error")
}
let mut result: duckdb_result = mem::zeroed();
let sql = CString::new("select * from integers").unwrap();
if duckdb_query(con, sql.as_ptr() as *const c_char, &mut result) != duckdb_state_DuckDBSuccess {
panic!(
"SELECT error: {}",
CStr::from_ptr(result.error_message).to_string_lossy()
)
}
assert_eq!(result.row_count, 3);
assert_eq!(result.column_count, 2);
print_result(result);
duckdb_destroy_result(&mut result);
let mut stmt: duckdb_prepared_statement = ptr::null_mut();
let sql = CString::new("select * from integers where i>?").unwrap();
if duckdb_prepare(con, sql.as_ptr() as *const c_char, &mut stmt) != duckdb_state_DuckDBSuccess {
panic!("Prepare error");
}
if duckdb_bind_int32(stmt, 1, 4) != duckdb_state_DuckDBSuccess {
panic!("Bind params error");
}
if duckdb_execute_prepared(stmt, &mut result) != duckdb_state_DuckDBSuccess {
panic!("Execute prepared error");
}
assert_eq!(result.row_count, 2);
assert_eq!(result.column_count, 2);
print_result(result);
duckdb_destroy_result(&mut result);
if duckdb_bind_int32(stmt, 1, 5) != duckdb_state_DuckDBSuccess {
panic!("Bind params error");
}
if duckdb_execute_prepared(stmt, &mut result) != duckdb_state_DuckDBSuccess {
panic!("Execute prepared error");
}
assert_eq!(result.row_count, 1);
assert_eq!(result.column_count, 2);
print_result(result);
duckdb_destroy_result(&mut result);
duckdb_destroy_result(&mut result);
duckdb_disconnect(&mut con);
duckdb_close(&mut db);
}
}
}