1#include "duckdb/main/capi/capi_internal.hpp"
2
3using duckdb::Appender;
4using duckdb::AppenderWrapper;
5using duckdb::Connection;
6using duckdb::date_t;
7using duckdb::dtime_t;
8using duckdb::hugeint_t;
9using duckdb::interval_t;
10using duckdb::string_t;
11using duckdb::timestamp_t;
12
13duckdb_state duckdb_appender_create(duckdb_connection connection, const char *schema, const char *table,
14 duckdb_appender *out_appender) {
15 Connection *conn = reinterpret_cast<Connection *>(connection);
16
17 if (!connection || !table || !out_appender) {
18 return DuckDBError;
19 }
20 if (schema == nullptr) {
21 schema = DEFAULT_SCHEMA;
22 }
23 auto wrapper = new AppenderWrapper();
24 *out_appender = (duckdb_appender)wrapper;
25 try {
26 wrapper->appender = duckdb::make_uniq<Appender>(args&: *conn, args&: schema, args&: table);
27 } catch (std::exception &ex) {
28 wrapper->error = ex.what();
29 return DuckDBError;
30 } catch (...) { // LCOV_EXCL_START
31 wrapper->error = "Unknown create appender error";
32 return DuckDBError;
33 } // LCOV_EXCL_STOP
34 return DuckDBSuccess;
35}
36
37duckdb_state duckdb_appender_destroy(duckdb_appender *appender) {
38 if (!appender || !*appender) {
39 return DuckDBError;
40 }
41 duckdb_appender_close(appender: *appender);
42 auto wrapper = reinterpret_cast<AppenderWrapper *>(*appender);
43 if (wrapper) {
44 delete wrapper;
45 }
46 *appender = nullptr;
47 return DuckDBSuccess;
48}
49
50template <class FUN>
51duckdb_state duckdb_appender_run_function(duckdb_appender appender, FUN &&function) {
52 if (!appender) {
53 return DuckDBError;
54 }
55 auto wrapper = reinterpret_cast<AppenderWrapper *>(appender);
56 if (!wrapper->appender) {
57 return DuckDBError;
58 }
59 try {
60 function(*wrapper->appender);
61 } catch (std::exception &ex) {
62 wrapper->error = ex.what();
63 return DuckDBError;
64 } catch (...) { // LCOV_EXCL_START
65 wrapper->error = "Unknown error";
66 return DuckDBError;
67 } // LCOV_EXCL_STOP
68 return DuckDBSuccess;
69}
70
71const char *duckdb_appender_error(duckdb_appender appender) {
72 if (!appender) {
73 return nullptr;
74 }
75 auto wrapper = reinterpret_cast<AppenderWrapper *>(appender);
76 if (wrapper->error.empty()) {
77 return nullptr;
78 }
79 return wrapper->error.c_str();
80}
81
82duckdb_state duckdb_appender_begin_row(duckdb_appender appender) {
83 return DuckDBSuccess;
84}
85
86duckdb_state duckdb_appender_end_row(duckdb_appender appender) {
87 return duckdb_appender_run_function(appender, function: [&](Appender &appender) { appender.EndRow(); });
88}
89
90template <class T>
91duckdb_state duckdb_append_internal(duckdb_appender appender, T value) {
92 if (!appender) {
93 return DuckDBError;
94 }
95 auto *appender_instance = reinterpret_cast<AppenderWrapper *>(appender);
96 try {
97 appender_instance->appender->Append<T>(value);
98 } catch (std::exception &ex) {
99 appender_instance->error = ex.what();
100 return DuckDBError;
101 } catch (...) {
102 return DuckDBError;
103 }
104 return DuckDBSuccess;
105}
106
107duckdb_state duckdb_append_bool(duckdb_appender appender, bool value) {
108 return duckdb_append_internal<bool>(appender, value);
109}
110
111duckdb_state duckdb_append_int8(duckdb_appender appender, int8_t value) {
112 return duckdb_append_internal<int8_t>(appender, value);
113}
114
115duckdb_state duckdb_append_int16(duckdb_appender appender, int16_t value) {
116 return duckdb_append_internal<int16_t>(appender, value);
117}
118
119duckdb_state duckdb_append_int32(duckdb_appender appender, int32_t value) {
120 return duckdb_append_internal<int32_t>(appender, value);
121}
122
123duckdb_state duckdb_append_int64(duckdb_appender appender, int64_t value) {
124 return duckdb_append_internal<int64_t>(appender, value);
125}
126
127duckdb_state duckdb_append_hugeint(duckdb_appender appender, duckdb_hugeint value) {
128 hugeint_t internal;
129 internal.lower = value.lower;
130 internal.upper = value.upper;
131 return duckdb_append_internal<hugeint_t>(appender, value: internal);
132}
133
134duckdb_state duckdb_append_uint8(duckdb_appender appender, uint8_t value) {
135 return duckdb_append_internal<uint8_t>(appender, value);
136}
137
138duckdb_state duckdb_append_uint16(duckdb_appender appender, uint16_t value) {
139 return duckdb_append_internal<uint16_t>(appender, value);
140}
141
142duckdb_state duckdb_append_uint32(duckdb_appender appender, uint32_t value) {
143 return duckdb_append_internal<uint32_t>(appender, value);
144}
145
146duckdb_state duckdb_append_uint64(duckdb_appender appender, uint64_t value) {
147 return duckdb_append_internal<uint64_t>(appender, value);
148}
149
150duckdb_state duckdb_append_float(duckdb_appender appender, float value) {
151 return duckdb_append_internal<float>(appender, value);
152}
153
154duckdb_state duckdb_append_double(duckdb_appender appender, double value) {
155 return duckdb_append_internal<double>(appender, value);
156}
157
158duckdb_state duckdb_append_date(duckdb_appender appender, duckdb_date value) {
159 return duckdb_append_internal<date_t>(appender, value: date_t(value.days));
160}
161
162duckdb_state duckdb_append_time(duckdb_appender appender, duckdb_time value) {
163 return duckdb_append_internal<dtime_t>(appender, value: dtime_t(value.micros));
164}
165
166duckdb_state duckdb_append_timestamp(duckdb_appender appender, duckdb_timestamp value) {
167 return duckdb_append_internal<timestamp_t>(appender, value: timestamp_t(value.micros));
168}
169
170duckdb_state duckdb_append_interval(duckdb_appender appender, duckdb_interval value) {
171 interval_t interval;
172 interval.months = value.months;
173 interval.days = value.days;
174 interval.micros = value.micros;
175 return duckdb_append_internal<interval_t>(appender, value: interval);
176}
177
178duckdb_state duckdb_append_null(duckdb_appender appender) {
179 return duckdb_append_internal<std::nullptr_t>(appender, value: nullptr);
180}
181
182duckdb_state duckdb_append_varchar(duckdb_appender appender, const char *val) {
183 return duckdb_append_internal<const char *>(appender, value: val);
184}
185
186duckdb_state duckdb_append_varchar_length(duckdb_appender appender, const char *val, idx_t length) {
187 return duckdb_append_internal<string_t>(appender, value: string_t(val, length));
188}
189duckdb_state duckdb_append_blob(duckdb_appender appender, const void *data, idx_t length) {
190 auto value = duckdb::Value::BLOB(data: (duckdb::const_data_ptr_t)data, len: length);
191 return duckdb_append_internal<duckdb::Value>(appender, value);
192}
193
194duckdb_state duckdb_appender_flush(duckdb_appender appender) {
195 return duckdb_appender_run_function(appender, function: [&](Appender &appender) { appender.Flush(); });
196}
197
198duckdb_state duckdb_appender_close(duckdb_appender appender) {
199 return duckdb_appender_run_function(appender, function: [&](Appender &appender) { appender.Close(); });
200}
201
202duckdb_state duckdb_append_data_chunk(duckdb_appender appender, duckdb_data_chunk chunk) {
203 if (!chunk) {
204 return DuckDBError;
205 }
206 auto data_chunk = (duckdb::DataChunk *)chunk;
207 return duckdb_appender_run_function(appender, function: [&](Appender &appender) { appender.AppendDataChunk(value&: *data_chunk); });
208}
209