1#![allow(non_upper_case_globals)]
2#![allow(non_camel_case_types)]
3#![allow(non_snake_case)]
4#![allow(deref_nullptr)]
5#![allow(improper_ctypes)]
6
7mod arrow_c_data;
9pub use arrow_c_data::{ArrowArray, ArrowSchema};
10
11#[allow(clippy::all, unsafe_op_in_unsafe_fn)]
12mod bindings {
13 use crate::arrow_c_data::{ArrowArray, ArrowSchema};
15
16 include!(concat!(env!("OUT_DIR"), "/bindgen.rs"));
17}
18#[allow(clippy::all)]
19pub use bindings::*;
20
21mod string;
22pub use string::*;
23
24pub const DuckDBError: duckdb_state = duckdb_state_DuckDBError;
25pub const DuckDBSuccess: duckdb_state = duckdb_state_DuckDBSuccess;
26
27pub use self::error::*;
28mod error;
29
30#[cfg(test)]
31mod tests {
32 use super::*;
33 use std::{
34 ffi::{CStr, CString},
35 mem,
36 os::raw::c_char,
37 ptr,
38 };
39
40 use arrow::{
41 array::{Array, Int32Array, StructArray},
42 datatypes::DataType,
43 ffi::{FFI_ArrowArray, FFI_ArrowSchema, from_ffi},
44 };
45
46 unsafe fn print_int_result(result: &mut duckdb_result) {
47 unsafe {
48 for i in 0..duckdb_column_count(result) {
49 print!("{} ", CStr::from_ptr(duckdb_column_name(result, i)).to_string_lossy());
50 }
51 println!();
52 for row_idx in 0..duckdb_row_count(result) {
54 for col_idx in 0..duckdb_column_count(result) {
55 let val = duckdb_value_int32(result, col_idx, row_idx);
56 print!("{val} ");
57 }
58 println!();
59 }
60 }
61 }
62
63 #[test]
64 fn test_query_arrow() {
65 unsafe {
66 let mut db: duckdb_database = ptr::null_mut();
68 let mut con: duckdb_connection = ptr::null_mut();
69 if duckdb_open(ptr::null_mut(), &mut db) != duckdb_state_DuckDBSuccess {
70 panic!("duckdb_open error")
71 }
72 if duckdb_connect(db, &mut con) != duckdb_state_DuckDBSuccess {
73 panic!("duckdb_connect error")
74 }
75 let sql = CString::new("CREATE TABLE integers(i INTEGER, j INTEGER);").unwrap();
77 if duckdb_query(con, sql.as_ptr() as *const c_char, ptr::null_mut()) != duckdb_state_DuckDBSuccess {
78 panic!("CREATE TABLE error")
79 }
80
81 let sql = CString::new("INSERT INTO integers VALUES (3, 4), (5, 6), (7, NULL);").unwrap();
83 let mut result: duckdb_arrow = ptr::null_mut();
84 if duckdb_query_arrow(con, sql.as_ptr() as *const c_char, &mut result) != duckdb_state_DuckDBSuccess {
85 panic!("INSERT error")
86 }
87 assert_eq!(duckdb_arrow_rows_changed(result), 3);
88 duckdb_destroy_arrow(&mut result);
89
90 let mut result: duckdb_arrow = ptr::null_mut();
92 let sql = CString::new("select i, j from integers order by i desc").unwrap();
93 if duckdb_query_arrow(con, sql.as_ptr() as *const c_char, &mut result) != duckdb_state_DuckDBSuccess {
94 panic!("SELECT error")
95 }
96 assert_eq!(duckdb_arrow_row_count(result), 3);
97 assert_eq!(duckdb_arrow_column_count(result), 2);
98
99 let mut arrays = FFI_ArrowArray::empty();
100 let mut schema = FFI_ArrowSchema::empty();
101 if duckdb_query_arrow_schema(
102 result,
103 &mut std::ptr::addr_of_mut!(schema) as *mut _ as *mut duckdb_arrow_schema,
104 ) != duckdb_state_DuckDBSuccess
105 {
106 panic!("SELECT error")
107 }
108 if duckdb_query_arrow_array(
109 result,
110 &mut std::ptr::addr_of_mut!(arrays) as *mut _ as *mut duckdb_arrow_array,
111 ) != duckdb_state_DuckDBSuccess
112 {
113 panic!("SELECT error")
114 }
115 let array_data = from_ffi(arrays, &schema).expect("ok");
116 let struct_array = StructArray::from(array_data);
117 assert_eq!(struct_array.len(), 3);
118 assert_eq!(struct_array.columns().len(), 2);
119 assert_eq!(struct_array.column(0).data_type(), &DataType::Int32);
120 assert_eq!(struct_array.column(1).data_type(), &DataType::Int32);
121 let arr_i = struct_array.column(0).as_any().downcast_ref::<Int32Array>().unwrap();
122 assert_eq!(arr_i.value(0), 7);
123 assert_eq!(arr_i.value(1), 5);
124 assert_eq!(arr_i.value(2), 3);
125 let arr_j = struct_array.column(1).as_any().downcast_ref::<Int32Array>().unwrap();
126 assert!(arr_j.is_null(0));
127 assert_eq!(arr_j.value(1), 6);
128 assert_eq!(arr_j.value(2), 4);
129
130 let mut arrays: duckdb_arrow_array = ptr::null_mut();
131 if duckdb_query_arrow_array(result, &mut arrays) != duckdb_state_DuckDBSuccess {
132 panic!("SELECT error")
133 }
134 assert!(arrays.is_null());
135 duckdb_destroy_arrow(&mut result);
136 duckdb_disconnect(&mut con);
137 duckdb_close(&mut db);
138 }
139 }
140
141 #[test]
142 fn basic_api_usage() {
143 unsafe {
144 let mut db: duckdb_database = ptr::null_mut();
146 let mut con: duckdb_connection = ptr::null_mut();
147 if duckdb_open(ptr::null_mut(), &mut db) != duckdb_state_DuckDBSuccess {
148 panic!("duckdb_open error")
149 }
150 if duckdb_connect(db, &mut con) != duckdb_state_DuckDBSuccess {
151 panic!("duckdb_connect error")
152 }
153 let sql = CString::new("CREATE TABLE integers(i INTEGER, j INTEGER);").unwrap();
155 if duckdb_query(con, sql.as_ptr() as *const c_char, ptr::null_mut()) != duckdb_state_DuckDBSuccess {
156 panic!("CREATE TABLE error")
157 }
158 let sql = CString::new("INSERT INTO integers VALUES (3, 4), (5, 6), (7, NULL);").unwrap();
160 if duckdb_query(con, sql.as_ptr() as *const c_char, ptr::null_mut()) != duckdb_state_DuckDBSuccess {
161 panic!("INSERT error")
162 }
163 let mut result: duckdb_result = mem::zeroed();
165 let sql = CString::new("select * from integers").unwrap();
166 if duckdb_query(con, sql.as_ptr() as *const c_char, &mut result) != duckdb_state_DuckDBSuccess {
167 panic!(
168 "SELECT error: {}",
169 CStr::from_ptr(duckdb_result_error(&mut result)).to_string_lossy()
170 )
171 }
172 assert_eq!(duckdb_row_count(&mut result), 3);
173 assert_eq!(duckdb_column_count(&mut result), 2);
174 print_int_result(&mut result);
175 duckdb_destroy_result(&mut result);
176
177 let mut stmt: duckdb_prepared_statement = ptr::null_mut();
179 let sql = CString::new("select * from integers where i>?").unwrap();
180 if duckdb_prepare(con, sql.as_ptr() as *const c_char, &mut stmt) != duckdb_state_DuckDBSuccess {
181 panic!("Prepare error");
182 }
183 if duckdb_bind_int32(stmt, 1, 4) != duckdb_state_DuckDBSuccess {
184 panic!("Bind params error");
185 }
186 if duckdb_execute_prepared(stmt, &mut result) != duckdb_state_DuckDBSuccess {
187 panic!("Execute prepared error");
188 }
189 assert_eq!(duckdb_row_count(&mut result), 2);
190 assert_eq!(duckdb_column_count(&mut result), 2);
191 print_int_result(&mut result);
192 duckdb_destroy_result(&mut result);
193
194 if duckdb_bind_int32(stmt, 1, 5) != duckdb_state_DuckDBSuccess {
196 panic!("Bind params error");
197 }
198 if duckdb_execute_prepared(stmt, &mut result) != duckdb_state_DuckDBSuccess {
199 panic!("Execute prepared error");
200 }
201 assert_eq!(duckdb_row_count(&mut result), 1);
202 assert_eq!(duckdb_column_count(&mut result), 2);
203 print_int_result(&mut result);
204 duckdb_destroy_result(&mut result);
205 duckdb_destroy_prepare(&mut stmt);
206
207 duckdb_disconnect(&mut con);
209 duckdb_close(&mut db);
210 }
211 }
212}