Skip to content

Commit 4955ddd

Browse files
committed
codegen only used functions in duckdb C API
Signed-off-by: Mikhail Kot <mikhail@spiraldb.com>
1 parent cb82828 commit 4955ddd

4 files changed

Lines changed: 191 additions & 51 deletions

File tree

vortex-duckdb/build.rs

Lines changed: 156 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,145 @@ const SOURCE_FILES: [&str; 17] = [
4444
"cpp/vector_buffer.cpp",
4545
];
4646

47+
// Duckdb C API function we use.
48+
// This lowers codegen'd src/cpp.rs by four times.
49+
const DUCKDB_C_API_FUNCTIONS: [&str; 134] = [
50+
"duckdb_array_type_array_size",
51+
"duckdb_array_type_child_type",
52+
"duckdb_array_vector_get_child",
53+
"duckdb_client_context_try_get_current_setting",
54+
"duckdb_close",
55+
"duckdb_column_count",
56+
"duckdb_column_logical_type",
57+
"duckdb_column_name",
58+
"duckdb_column_type",
59+
"duckdb_config_count",
60+
"duckdb_connect",
61+
"duckdb_create_array_type",
62+
"duckdb_create_blob",
63+
"duckdb_create_bool",
64+
"duckdb_create_config",
65+
"duckdb_create_data_chunk",
66+
"duckdb_create_date",
67+
"duckdb_create_decimal",
68+
"duckdb_create_decimal_type",
69+
"duckdb_create_double",
70+
"duckdb_create_float",
71+
"duckdb_create_int16",
72+
"duckdb_create_int32",
73+
"duckdb_create_int64",
74+
"duckdb_create_int8",
75+
"duckdb_create_list_type",
76+
"duckdb_create_logical_type",
77+
"duckdb_create_map_type",
78+
"duckdb_create_null_value",
79+
"duckdb_create_selection_vector",
80+
"duckdb_create_struct_type",
81+
"duckdb_create_time",
82+
"duckdb_create_timestamp",
83+
"duckdb_create_timestamp_ms",
84+
"duckdb_create_timestamp_ns",
85+
"duckdb_create_timestamp_s",
86+
"duckdb_create_timestamp_tz",
87+
"duckdb_create_uint16",
88+
"duckdb_create_uint32",
89+
"duckdb_create_uint64",
90+
"duckdb_create_uint8",
91+
"duckdb_create_union_type",
92+
"duckdb_create_varchar_length",
93+
"duckdb_create_vector",
94+
"duckdb_data_chunk_get_column_count",
95+
"duckdb_data_chunk_get_size",
96+
"duckdb_data_chunk_get_vector",
97+
"duckdb_data_chunk_reset",
98+
"duckdb_data_chunk_set_size",
99+
"duckdb_data_chunk_to_string",
100+
"duckdb_data_chunk_verify",
101+
"duckdb_decimal_scale",
102+
"duckdb_decimal_width",
103+
"duckdb_destroy_client_context",
104+
"duckdb_destroy_config",
105+
"duckdb_destroy_data_chunk",
106+
"duckdb_destroy_logical_type",
107+
"duckdb_destroy_result",
108+
"duckdb_destroy_selection_vector",
109+
"duckdb_destroy_value",
110+
"duckdb_destroy_vector",
111+
"duckdb_disconnect",
112+
"duckdb_fetch_chunk",
113+
"duckdb_free",
114+
"duckdb_geometry_type_get_crs",
115+
"duckdb_get_blob",
116+
"duckdb_get_bool",
117+
"duckdb_get_config_flag",
118+
"duckdb_get_date",
119+
"duckdb_get_decimal",
120+
"duckdb_get_double",
121+
"duckdb_get_float",
122+
"duckdb_get_hugeint",
123+
"duckdb_get_int16",
124+
"duckdb_get_int32",
125+
"duckdb_get_int64",
126+
"duckdb_get_int8",
127+
"duckdb_get_list_child",
128+
"duckdb_get_list_size",
129+
"duckdb_get_struct_child",
130+
"duckdb_get_time",
131+
"duckdb_get_time_ns",
132+
"duckdb_get_timestamp",
133+
"duckdb_get_timestamp_ms",
134+
"duckdb_get_timestamp_ns",
135+
"duckdb_get_timestamp_s",
136+
"duckdb_get_timestamp_tz",
137+
"duckdb_get_type_id",
138+
"duckdb_get_uhugeint",
139+
"duckdb_get_uint16",
140+
"duckdb_get_uint32",
141+
"duckdb_get_uint64",
142+
"duckdb_get_uint8",
143+
"duckdb_get_value_type",
144+
"duckdb_get_varchar",
145+
"duckdb_is_null_value",
146+
"duckdb_library_version",
147+
"duckdb_list_type_child_type",
148+
"duckdb_list_vector_get_child",
149+
"duckdb_list_vector_get_size",
150+
"duckdb_list_vector_reserve",
151+
"duckdb_list_vector_set_size",
152+
"duckdb_malloc",
153+
"duckdb_map_type_key_type",
154+
"duckdb_map_type_value_type",
155+
"duckdb_open",
156+
"duckdb_open_ext",
157+
"duckdb_query",
158+
"duckdb_result_error",
159+
"duckdb_row_count",
160+
"duckdb_rows_changed",
161+
"duckdb_selection_vector_get_data_ptr",
162+
"duckdb_set_config",
163+
"duckdb_string_t_data",
164+
"duckdb_string_t_length",
165+
"duckdb_struct_type_child_count",
166+
"duckdb_struct_type_child_name",
167+
"duckdb_struct_type_child_type",
168+
"duckdb_struct_vector_get_child",
169+
"duckdb_union_type_member_count",
170+
"duckdb_union_type_member_name",
171+
"duckdb_union_type_member_type",
172+
"duckdb_value_to_string",
173+
"duckdb_vector_assign_string_element",
174+
"duckdb_vector_assign_string_element_len",
175+
"duckdb_vector_ensure_validity_writable",
176+
"duckdb_vector_flatten",
177+
"duckdb_vector_get_column_type",
178+
"duckdb_vector_get_data",
179+
"duckdb_vector_get_validity",
180+
"duckdb_vector_reference_value",
181+
"duckdb_vector_reference_vector",
182+
"duckdb_vector_size",
183+
"duckdb_vector_to_string",
184+
];
185+
47186
const DOWNLOAD_MAX_RETRIES: i32 = 3;
48187
const DOWNLOAD_TIMEOUT: u64 = 90;
49188

@@ -218,7 +357,7 @@ fn build_duckdb(version: &DuckDBVersion, duckdb_repo_dir: &Path) {
218357
("1", "0")
219358
};
220359

221-
// If we're building from a commit we need to build httpfs and benchmark
360+
// If we're building from a commit we need to build httpfs and benchmark
222361
// extensions statically, otherwise DuckDB tries to load them from an http
223362
// endpoint with version 0.0.1 (all non-tagged builds) which doesn't exist.
224363
// httpfs static build also requires CURL dev headers
@@ -306,31 +445,41 @@ fn try_build_duckdb(
306445

307446
/// Generate rust functions with bindgen from C sources.
308447
fn bindgen_c2rust(crate_dir: &Path, duckdb_include_dir: &Path) {
309-
let bindings = bindgen::Builder::default()
448+
let mut builder = bindgen::Builder::default()
310449
.header("cpp/include/duckdb_vx.h")
311450
.override_abi(Abi::CUnwind, ".*")
312-
// Allow for auto-generated cpp.rs code.
313451
.raw_line("#![allow(dead_code)]")
314452
.raw_line("#![allow(non_camel_case_types)]")
315453
.raw_line("#![allow(non_upper_case_globals)]")
316454
.raw_line("#![allow(non_snake_case)]")
317455
.raw_line("#![allow(clippy::absolute_paths)]")
318456
.raw_line("#![allow(clippy::suspicious_doc_comments)]")
319457
.raw_line("#![allow(clippy::enum_variant_names)]")
458+
.allowlist_function("duckdb_vx_.*")
459+
.allowlist_type("duckdb_vx_.*")
460+
.allowlist_type("DUCKDB_VX_.*")
461+
.allowlist_var("DUCKDB_VX_.*")
462+
// Two types read from raw vector data
463+
.allowlist_type("duckdb_list_entry")
464+
.allowlist_type("duckdb_column_statistics")
320465
// Add the #[must_use] attribute to FFI functions that return results.
321466
.must_use_type("duckdb_state")
322467
.rustified_enum("duckdb_state")
323468
.rustified_enum("DUCKDB_VX_EXPR_CLASS")
324469
.rustified_enum("DUCKDB_VX_EXPR_TYPE")
325470
.rustified_enum("DUCKDB_VX_TABLE_FILTER_TYPE")
326-
.rustified_enum("DUCKDB_VX_VECTOR_TYPE")
327471
.rustified_non_exhaustive_enum("DUCKDB_TYPE")
328472
.size_t_is_usize(true)
329473
.clang_arg(format!("-I{}", duckdb_include_dir.display()))
330474
.clang_arg(format!("-I{}", crate_dir.join("cpp/include").display()))
331475
.generate_comments(true)
332-
.parse_callbacks(Box::new(BindgenCargoCallbacks))
333-
.generate();
476+
.parse_callbacks(Box::new(BindgenCargoCallbacks));
477+
478+
for function in DUCKDB_C_API_FUNCTIONS {
479+
builder = builder.allowlist_function(function);
480+
}
481+
482+
let bindings = builder.generate();
334483

335484
let bindings = match bindings {
336485
Ok(b) => b,
@@ -340,12 +489,7 @@ fn bindgen_c2rust(crate_dir: &Path, duckdb_include_dir: &Path) {
340489
}
341490
};
342491
let out_path = crate_dir.join("src/cpp.rs");
343-
let new_contents = bindings.to_string();
344-
let write = match fs::read_to_string(&out_path) {
345-
Ok(existing) => existing != new_contents,
346-
Err(_) => true,
347-
};
348-
if write && let Err(e) = fs::write(&out_path, new_contents) {
492+
if let Err(e) = fs::write(&out_path, bindings.to_string()) {
349493
println!("cargo:error=Failed to write Rust bindings: {e}");
350494
exit(1);
351495
}

vortex-duckdb/cbindgen.toml

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,23 @@ cpp_compat = true
33
usize_is_size_t = true
44
style = "type"
55
braces = "SameLine"
6+
documentation = false
7+
pragma_once = true
68

79
header = """
810
// SPDX-License-Identifier: Apache-2.0
911
// SPDX-FileCopyrightText: Copyright the Vortex contributors
10-
1112
//
1213
// THIS FILE IS AUTO-GENERATED, DO NOT MAKE EDITS DIRECTLY
1314
//
1415
1516
// clang-format off
1617
17-
#ifdef __cplusplus
18-
extern "C" {
19-
#endif
20-
2118
#include "duckdb.h"
2219
"""
23-
trailer = """
24-
#ifdef __cplusplus
25-
}
26-
#endif
2720

28-
// clang-format on
29-
"""
21+
trailer = """
22+
// clang-format on"""
3023

3124
[fn]
3225
prefix = "extern"

vortex-duckdb/include/vortex.h

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,24 @@
11
// SPDX-License-Identifier: Apache-2.0
22
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3-
43
//
54
// THIS FILE IS AUTO-GENERATED, DO NOT MAKE EDITS DIRECTLY
65
//
76

87
// clang-format off
98

10-
#ifdef __cplusplus
11-
extern "C" {
12-
#endif
13-
149
#include "duckdb.h"
1510

1611

12+
#pragma once
13+
1714
#ifdef __cplusplus
1815
extern "C" {
1916
#endif // __cplusplus
2017

21-
/**
22-
* Global symbol visibility in the Vortex extension:
23-
* - Rust functions use C ABI with "_rust" suffix (e.g., vortex_init_rust)
24-
* - C++ wrapper functions have the expected name without suffix (e.g., vortex_init)
25-
* - C++ wrappers are annotated with DUCKDB_EXTENSION_API to ensure global visibility
26-
* - C++ wrappers call the corresponding Rust functions
27-
*
28-
* This ensures DuckDB can find the symbols when loading the extension.
29-
*
30-
* The DuckDB extension ABI initialization function.
31-
*/
3218
extern void vortex_init_rust(duckdb_database db);
3319

34-
/**
35-
* The DuckDB extension ABI version function.
36-
* This function returns the version of the DuckDB library the extension is built against.
37-
*/
3820
extern const char *vortex_version_rust(void);
3921

40-
/**
41-
* An additional function we export to expose the version of the extension itself to C++ code.
42-
*/
4322
extern const char *vortex_extension_version_rust(void);
4423

4524
extern void duckdb_table_function_to_string(void *bind_data, duckdb_vx_string_map map);
@@ -112,8 +91,4 @@ extern void duckdb_copy_function_copy_to_finalize(void *global_data, duckdb_vx_e
11291
} // extern "C"
11392
#endif // __cplusplus
11493

115-
#ifdef __cplusplus
116-
}
117-
#endif
118-
11994
// clang-format on

vortex-duckdb/src/duckdb/logical_type.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,33 @@ use vortex::error::VortexExpect;
99
use vortex::error::VortexResult;
1010
use vortex::error::vortex_bail;
1111

12-
use crate::cpp::*;
12+
use crate::cpp::DUCKDB_TYPE;
13+
use crate::cpp::duckdb_array_type_array_size;
14+
use crate::cpp::duckdb_array_type_child_type;
15+
use crate::cpp::duckdb_create_array_type;
16+
use crate::cpp::duckdb_create_decimal_type;
17+
use crate::cpp::duckdb_create_list_type;
18+
use crate::cpp::duckdb_create_logical_type;
19+
use crate::cpp::duckdb_create_struct_type;
20+
use crate::cpp::duckdb_decimal_scale;
21+
use crate::cpp::duckdb_decimal_width;
22+
use crate::cpp::duckdb_destroy_logical_type;
23+
use crate::cpp::duckdb_geometry_type_get_crs;
24+
use crate::cpp::duckdb_get_type_id;
25+
use crate::cpp::duckdb_list_type_child_type;
26+
use crate::cpp::duckdb_logical_type;
27+
use crate::cpp::duckdb_map_type_key_type;
28+
use crate::cpp::duckdb_map_type_value_type;
29+
use crate::cpp::duckdb_struct_type_child_count;
30+
use crate::cpp::duckdb_struct_type_child_name;
31+
use crate::cpp::duckdb_struct_type_child_type;
32+
use crate::cpp::duckdb_union_type_member_count;
33+
use crate::cpp::duckdb_union_type_member_name;
34+
use crate::cpp::duckdb_union_type_member_type;
35+
use crate::cpp::duckdb_vx_create_geometry;
36+
use crate::cpp::duckdb_vx_logical_type_copy;
37+
use crate::cpp::duckdb_vx_logical_type_stringify;
38+
use crate::cpp::idx_t;
1339
use crate::duckdb::ddb_string::DDBString;
1440
use crate::lifetime_wrapper;
1541

@@ -402,6 +428,8 @@ floating_type!(Double, f64);
402428
#[cfg(test)]
403429
mod tests {
404430
use super::*;
431+
use crate::cpp::duckdb_create_map_type;
432+
use crate::cpp::duckdb_create_union_type;
405433

406434
#[test]
407435
fn test_clone_logical_type() {

0 commit comments

Comments
 (0)