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+
99DUCKDB_INCLUDES_BEGIN
1010#include " duckdb/function/copy_function.hpp"
1111#include " duckdb/main/capi/capi_internal.hpp"
@@ -15,161 +15,122 @@ DUCKDB_INCLUDES_BEGIN
1515DUCKDB_INCLUDES_END
1616
1717using 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
8264unique_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 ©_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
0 commit comments