Skip to content

Commit cbe383d

Browse files
committed
better
Signed-off-by: Mikhail Kot <mikhail@spiraldb.com>
1 parent c84205b commit cbe383d

15 files changed

Lines changed: 281 additions & 478 deletions

File tree

vortex-duckdb/build.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,6 @@ fn main() {
483483
let duckdb_include_dir = inner_dir.join("src").join("include");
484484
println!("cargo:rerun-if-changed=cpp/include");
485485
c2rust(&crate_dir, &duckdb_include_dir);
486-
cpp(&duckdb_include_dir);
487486
rust2c(&crate_dir);
487+
cpp(&duckdb_include_dir);
488488
}

vortex-duckdb/cbindgen.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
language = "C"
22
cpp_compat = true
3+
usize_is_size_t = true
4+
style = "type"
5+
braces = "SameLine"
36

47
header = """
58
// SPDX-License-Identifier: Apache-2.0
Lines changed: 68 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
// SPDX-License-Identifier: Apache-2.0
22
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3-
4-
#include "duckdb_vx.h"
53
#include "duckdb_vx/data.hpp"
64
#include "duckdb_vx/error.hpp"
7-
5+
#include "duckdb_vx/table_function.h"
6+
#include "vortex.h"
87
#include "duckdb_vx/duckdb_diagnostics.h"
8+
99
DUCKDB_INCLUDES_BEGIN
1010
#include "duckdb/function/copy_function.hpp"
1111
#include "duckdb/main/capi/capi_internal.hpp"
@@ -15,161 +15,122 @@ DUCKDB_INCLUDES_BEGIN
1515
DUCKDB_INCLUDES_END
1616

1717
using namespace duckdb;
18+
using vortex::CData;
19+
using vortex::IntoErrString;
1820

19-
namespace vortex {
20-
21-
struct CCopyBindData final : TableFunctionData {
22-
CCopyBindData(const duckdb_vx_copy_func_vtab_t vtab_p, unique_ptr<CData> ffi_data_p)
23-
: vtab(vtab_p), ffi_data(std::move(ffi_data_p)) {
24-
}
25-
26-
const duckdb_vx_copy_func_vtab_t vtab;
27-
unique_ptr<CData> ffi_data;
28-
};
29-
30-
struct CCopyGlobalData final : GlobalFunctionData {
31-
explicit CCopyGlobalData(unique_ptr<CData> ffi_data_p) : ffi_data(std::move(ffi_data_p)) {
21+
struct CopyBindData final : TableFunctionData {
22+
CopyBindData(unique_ptr<CData> ffi_data) : ffi_data(std::move(ffi_data)) {
3223
}
33-
3424
unique_ptr<CData> ffi_data;
3525
};
3626

37-
struct CCopyLocalData final : LocalFunctionData {
38-
explicit CCopyLocalData(unique_ptr<CData> ffi_data_p) : ffi_data(std::move(ffi_data_p)) {
27+
struct CopyGlobalData final : GlobalFunctionData {
28+
CopyGlobalData(unique_ptr<CData> ffi_data) : ffi_data(std::move(ffi_data)) {
3929
}
4030

4131
unique_ptr<CData> ffi_data;
4232
};
4333

44-
static duckdb_vx_copy_func_vtab_t copy_vtab_one;
45-
46-
unique_ptr<FunctionData> c_bind_one(ClientContext & /*context*/,
47-
CopyFunctionBindInput &info,
48-
const vector<string> &column_names,
49-
const vector<LogicalType> &column_types) {
50-
51-
auto c_column_names = vector<char *>();
52-
c_column_names.reserve(column_names.size());
53-
for (const auto &col_id : column_names) {
54-
c_column_names.push_back(const_cast<char *>(col_id.c_str()));
34+
unique_ptr<FunctionData> copy_to_bind(ClientContext &,
35+
CopyFunctionBindInput &,
36+
const vector<string> &column_names,
37+
const vector<LogicalType> &column_types) {
38+
vector<const char *> ffi_column_names(column_names.size());
39+
for (size_t i = 0; i < column_names.size(); ++i) {
40+
ffi_column_names[i] = column_names[i].c_str();
5541
}
5642

57-
auto c_column_types = vector<duckdb_logical_type>();
58-
c_column_types.reserve(c_column_types.size());
59-
for (auto &col_type : column_types) {
60-
c_column_types.push_back(reinterpret_cast<duckdb_logical_type>(const_cast<LogicalType *>(&col_type)));
43+
vector<duckdb_logical_type> ffi_column_types(column_types.size());
44+
for (size_t i = 0; i < column_types.size(); ++i) {
45+
// duckdb C api doesn't allow passing const LogicalTypes. We never
46+
// modify input in copy function.
47+
ffi_column_types[i] =
48+
reinterpret_cast<duckdb_logical_type>(const_cast<LogicalType *>(&column_types[i]));
6149
}
6250

6351
duckdb_vx_error error_out = nullptr;
64-
// TODO(myrrc): do we pass ownership of c_column_names in bind?
65-
// If yes, it's a UB as we'd double delete on function return
66-
auto ffi_bind_data = copy_vtab_one.bind(reinterpret_cast<duckdb_vx_copy_func_bind_input>(&info),
67-
c_column_names.data(),
68-
c_column_names.size(),
69-
c_column_types.data(),
70-
c_column_types.size(),
71-
&error_out);
52+
const duckdb_vx_data ffi_bind_data = duckdb_copy_function_copy_to_bind(ffi_column_names.data(),
53+
ffi_column_names.size(),
54+
ffi_column_types.data(),
55+
ffi_column_types.size(),
56+
&error_out);
7257
if (error_out) {
7358
throw BinderException(IntoErrString(error_out));
7459
}
75-
76-
return make_uniq<CCopyBindData>(
77-
// This should only be filled out once
78-
copy_vtab_one,
79-
unique_ptr<CData>(reinterpret_cast<CData *>(ffi_bind_data)));
60+
auto cdata = unique_ptr<CData>(reinterpret_cast<CData *>(ffi_bind_data));
61+
return make_uniq<CopyBindData>(std::move(cdata));
8062
}
8163

8264
unique_ptr<GlobalFunctionData>
83-
c_init_global(ClientContext &context, FunctionData &bind_data, const string &file_path) {
84-
auto &bind = bind_data.Cast<CCopyBindData>();
85-
duckdb_vx_error error_out = nullptr;
86-
auto global_data = bind.vtab.init_global(reinterpret_cast<duckdb_client_context>(&context),
87-
bind.ffi_data->DataPtr(),
88-
file_path.c_str(),
89-
&error_out);
90-
if (error_out) {
91-
throw ExecutorException(IntoErrString(error_out));
92-
}
65+
copy_to_initialize_global(ClientContext &context, FunctionData &bind_data, const string &file_path) {
66+
void *const ffi_bind = bind_data.Cast<CopyBindData>().ffi_data->DataPtr();
67+
const auto ffi_ctx = reinterpret_cast<duckdb_client_context>(&context);
9368

94-
return make_uniq<CCopyGlobalData>(unique_ptr<CData>(reinterpret_cast<CData *>(global_data)));
95-
}
96-
97-
unique_ptr<LocalFunctionData> c_init_local(ExecutionContext & /*context*/, FunctionData &bind_data) {
98-
auto &bind = bind_data.Cast<CCopyBindData>();
9969
duckdb_vx_error error_out = nullptr;
100-
auto data = bind.vtab.init_local(bind.ffi_data->DataPtr(), &error_out);
70+
const duckdb_vx_data ffi_global =
71+
duckdb_copy_function_copy_to_initialize_global(ffi_ctx, ffi_bind, file_path.c_str(), &error_out);
10172
if (error_out) {
10273
throw ExecutorException(IntoErrString(error_out));
10374
}
10475

105-
return make_uniq<CCopyLocalData>(unique_ptr<CData>(reinterpret_cast<CData *>(data)));
76+
auto cdata = unique_ptr<CData>(reinterpret_cast<CData *>(ffi_global));
77+
return make_uniq<CopyGlobalData>(std::move(cdata));
10678
}
10779

108-
void c_copy_to_sink(ExecutionContext & /*context*/,
109-
FunctionData &bind_data,
110-
GlobalFunctionData &gstate,
111-
LocalFunctionData &lstate,
112-
DataChunk &input) {
113-
auto &bind = bind_data.Cast<CCopyBindData>();
114-
auto &global = gstate.Cast<CCopyGlobalData>();
115-
auto &local = lstate.Cast<CCopyLocalData>();
80+
void copy_to_sink(ExecutionContext &,
81+
FunctionData &bind_data,
82+
GlobalFunctionData &gstate,
83+
LocalFunctionData &,
84+
DataChunk &input) {
85+
void *const ffi_bind = bind_data.Cast<CopyBindData>().ffi_data->DataPtr();
86+
void *const ffi_global = gstate.Cast<CopyGlobalData>().ffi_data->DataPtr();
87+
auto ffi_chunk = reinterpret_cast<duckdb_data_chunk>(&input);
11688
duckdb_vx_error error_out = nullptr;
117-
bind.vtab.copy_to_sink(bind.ffi_data->DataPtr(),
118-
global.ffi_data->DataPtr(),
119-
local.ffi_data->DataPtr(),
120-
reinterpret_cast<duckdb_data_chunk>(&input),
121-
&error_out);
89+
duckdb_copy_function_copy_to_sink(ffi_bind, ffi_global, ffi_chunk, &error_out);
12290
if (error_out) {
12391
throw ExecutorException(IntoErrString(error_out));
12492
}
12593
}
12694

127-
void copy_to_finalize(ClientContext & /*context*/, FunctionData &bind_data, GlobalFunctionData &gstate) {
128-
auto &bind = bind_data.Cast<CCopyBindData>();
129-
auto &global = gstate.Cast<CCopyGlobalData>();
95+
void copy_to_finalize(ClientContext &, FunctionData &, GlobalFunctionData &gstate) {
96+
void *const ffi_global = gstate.Cast<CopyGlobalData>().ffi_data->DataPtr();
13097
duckdb_vx_error error_out = nullptr;
131-
bind.vtab.copy_to_finalize(bind.ffi_data->DataPtr(), global.ffi_data->DataPtr(), &error_out);
98+
duckdb_copy_function_copy_to_finalize(ffi_global, &error_out);
13299
if (error_out) {
133100
throw ExecutorException(IntoErrString(error_out));
134101
}
135102
}
136103

137-
extern "C" duckdb_vx_copy_func_vtab_t *get_vtab_one() {
138-
return &copy_vtab_one;
139-
}
104+
extern "C" duckdb_state duckdb_vx_register_copy_function(duckdb_database ffi_db) {
105+
D_ASSERT(ffi_db);
106+
const DatabaseWrapper &wrapper = *reinterpret_cast<DatabaseWrapper *>(ffi_db);
107+
DatabaseInstance &db = *wrapper.database->instance;
140108

141-
extern "C" duckdb_state duckdb_vx_copy_func_register_vtab_one(duckdb_database ffi_db) {
142-
if (!ffi_db) {
143-
return DuckDBError;
144-
}
145-
146-
auto wrapper = reinterpret_cast<duckdb::DatabaseWrapper *>(ffi_db);
147-
auto db = wrapper->database->instance;
148-
auto copy_function = CopyFunction(copy_vtab_one.name);
149-
150-
copy_function.copy_to_bind = c_bind_one;
151-
copy_function.copy_to_initialize_global = c_init_global;
152-
copy_function.copy_to_initialize_local = c_init_local;
153-
154-
copy_function.copy_to_sink = c_copy_to_sink;
155-
copy_function.copy_to_finalize = copy_to_finalize;
156-
copy_function.extension = copy_vtab_one.extension;
109+
CopyFunction fn("vortex");
110+
fn.copy_to_bind = copy_to_bind;
111+
fn.copy_to_initialize_global = copy_to_initialize_global;
112+
fn.copy_to_initialize_local = [](auto &, auto &) {
113+
return make_uniq<LocalFunctionData>();
114+
};
115+
fn.copy_to_sink = copy_to_sink;
116+
fn.copy_to_finalize = copy_to_finalize;
117+
fn.extension = "vortex";
157118

158119
// TODO(joe): expose this via c our api
159-
copy_function.execution_mode = [](bool /*preserve_insertion_order*/, bool /*supports_batch_index*/) {
120+
fn.execution_mode = [](bool, bool) {
160121
return CopyFunctionExecutionMode::REGULAR_COPY_TO_FILE;
161122
};
162123
// TODO(joe): handle parameters as in table_function
163124

164125
try {
165-
auto &system_catalog = Catalog::GetSystemCatalog(*db);
166-
auto data = CatalogTransaction::GetSystemTransaction(*db);
167-
CreateCopyFunctionInfo copy_info(std::move(copy_function));
126+
Catalog &system_catalog = Catalog::GetSystemCatalog(db);
127+
CatalogTransaction data = CatalogTransaction::GetSystemTransaction(db);
128+
CreateCopyFunctionInfo copy_info(std::move(fn));
168129
system_catalog.CreateCopyFunction(data, copy_info);
169-
} catch (...) {
130+
} catch (const std::exception &e) {
131+
ErrorData data(e);
132+
DUCKDB_LOG_ERROR(db, "Failed to create Vortex copy function:\t" + data.Message());
170133
return DuckDBError;
171134
}
172135
return DuckDBSuccess;
173136
}
174-
175-
} // namespace vortex

vortex-duckdb/cpp/include/duckdb_vx/copy_function.h

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,16 @@
11
// SPDX-License-Identifier: Apache-2.0
22
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3-
4-
/**
5-
* We redefine a C API for DuckDB Copy Functions used to copy/write values from duckdb to a vortex file.
6-
* See table_filter.h for more info
7-
*/
83
#pragma once
9-
104
#include "data.h"
115
#include "error.h"
12-
#include "logical_type.h"
136
#include "duckdb_vx/data.h"
147

15-
#ifdef __cplusplus /* If compiled as C++, use C ABI */
8+
#ifdef __cplusplus
169
extern "C" {
1710
#endif
1811

19-
// Info passed into the bind callback. The callback should set error or else add result columns.
2012
typedef struct duckdb_vx_copy_func_bind_input_ *duckdb_vx_copy_func_bind_input;
2113

22-
// Input data passed into the init_global and init_local callbacks.
2314
typedef struct {
2415
const void *bind_data;
2516
const void *local_state;
@@ -32,6 +23,10 @@ typedef struct {
3223
// PARALLEL_COPY_TO_FILE,
3324
// BATCH_COPY_TO_FILE
3425
// } copy_function_execution_mode;
26+
//
27+
// TODO(joe): expose via c api
28+
// copy_function_execution_mode (*execution_mode)(bool preserve_insertion_order, bool
29+
// supports_batch_index);
3530

3631
// A transparent DuckDB copy function vtable, which can be used to configure a copy function.
3732
typedef struct {
@@ -63,17 +58,10 @@ typedef struct {
6358

6459
void (*copy_to_finalize)(const void *bind_data, void *global_data, duckdb_vx_error *error_out);
6560

66-
// TODO(joe): expose via c api
67-
// copy_function_execution_mode (*execution_mode)(bool preserve_insertion_order, bool
68-
// supports_batch_index);
6961
} duckdb_vx_copy_func_vtab_t;
7062

71-
// Due to a limitation in the copy function duckdb api we have to have global (copy) vtabs.
72-
duckdb_vx_copy_func_vtab_t *get_vtab_one();
73-
74-
// A single function for configuring the DuckDB table function vtable.
75-
duckdb_state duckdb_vx_copy_func_register_vtab_one(duckdb_database ffi_db);
63+
duckdb_state duckdb_vx_register_copy_function(duckdb_database ffi_db);
7664

77-
#ifdef __cplusplus /* End C ABI */
65+
#ifdef __cplusplus
7866
};
7967
#endif

vortex-duckdb/cpp/table_function.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,7 @@ struct CTableBindData final : FunctionData {
3737
};
3838

3939
unique_ptr<FunctionData> CTableBindData::Copy() const {
40-
duckdb_vx_error error_out = nullptr;
41-
const auto copied_ffi_data = duckdb_table_function_bind_data_clone(ffi_data->DataPtr(), &error_out);
42-
if (error_out) {
43-
throw BinderException(IntoErrString(error_out));
44-
}
45-
40+
const auto copied_ffi_data = duckdb_table_function_bind_data_clone(ffi_data->DataPtr());
4641
auto ffi_data_p = unique_ptr<CData>(reinterpret_cast<CData *>(copied_ffi_data));
4742
return make_uniq<CTableBindData>(std::move(ffi_data_p), types);
4843
}

vortex-duckdb/include/vortex.h

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ extern void duckdb_table_function_to_string(void *bind_data, duckdb_vx_string_ma
4646

4747
extern
4848
bool duckdb_table_function_statistics(const void *bind_data,
49-
uintptr_t column_index,
49+
size_t column_index,
5050
duckdb_column_statistics *stats_out);
5151

5252
extern double duckdb_table_function_scan_progress(void *global_state);
@@ -85,9 +85,28 @@ duckdb_vx_data duckdb_table_function_bind(duckdb_client_context ctx,
8585
duckdb_vx_tfunc_bind_result bind_result,
8686
duckdb_vx_error *error_out);
8787

88+
extern duckdb_vx_data duckdb_table_function_bind_data_clone(const void *bind_data);
89+
90+
extern
91+
duckdb_vx_data duckdb_copy_function_copy_to_bind(const char *const *column_names,
92+
size_t column_name_count,
93+
const duckdb_logical_type *column_types,
94+
size_t column_type_count,
95+
duckdb_vx_error *error_out);
96+
8897
extern
89-
duckdb_vx_data duckdb_table_function_bind_data_clone(const void *bind_data,
90-
duckdb_vx_error *error_out);
98+
duckdb_vx_data duckdb_copy_function_copy_to_initialize_global(duckdb_client_context client_context,
99+
const void *bind_data,
100+
const char *file_path,
101+
duckdb_vx_error *error_out);
102+
103+
extern
104+
void duckdb_copy_function_copy_to_sink(const void *bind_data,
105+
void *global_data,
106+
duckdb_data_chunk data_chunk,
107+
duckdb_vx_error *error_out);
108+
109+
extern void duckdb_copy_function_copy_to_finalize(void *global_data, duckdb_vx_error *error_out);
91110

92111
#ifdef __cplusplus
93112
} // extern "C"

vortex-duckdb/src/convert/dtype.rs

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ use std::sync::Arc;
3333

3434
use vortex::dtype::DType;
3535
use vortex::dtype::DecimalDType;
36-
use vortex::dtype::FieldName;
3736
use vortex::dtype::Nullability;
3837
use vortex::dtype::PType;
3938
use vortex::dtype::PType::F32;
@@ -177,20 +176,6 @@ impl FromLogicalType for DType {
177176
}
178177
}
179178

180-
pub fn from_duckdb_table<'a, I, S>(iter: I) -> VortexResult<StructFields>
181-
where
182-
I: Iterator<Item = (S, &'a LogicalTypeRef, Nullability)>,
183-
S: AsRef<str>,
184-
{
185-
iter.map(|(name, type_, nullability)| {
186-
Ok((
187-
FieldName::from(name.as_ref()),
188-
DType::from_logical_type(type_, nullability)?,
189-
))
190-
})
191-
.collect::<VortexResult<StructFields>>()
192-
}
193-
194179
impl TryFrom<DType> for LogicalType {
195180
type Error = VortexError;
196181

0 commit comments

Comments
 (0)