duckdb 0.4.1-dev2.0 → 0.4.1-dev2127.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Makefile +2 -2
- package/binding.gyp +8 -5
- package/lib/duckdb.js +404 -80
- package/package.json +3 -1
- package/src/connection.cpp +116 -136
- package/src/data_chunk.cpp +185 -0
- package/src/database.cpp +72 -22
- package/src/duckdb.cpp +83036 -41196
- package/src/duckdb.hpp +7907 -4256
- package/src/duckdb_node.cpp +1 -0
- package/src/duckdb_node.hpp +57 -18
- package/src/parquet-amalgamation.cpp +28578 -27929
- package/src/parquet-amalgamation.hpp +112 -114
- package/src/statement.cpp +142 -31
- package/test/data_type_support.test.js +83 -13
- package/test/extension.test.js +1 -1
- package/test/jsdoc.test.js +60 -0
- package/test/query_result.test.js +23 -0
- package/test/syntax_error.test.js +16 -0
- package/test/udf.test.js +172 -107
package/src/connection.cpp
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
#include "duckdb.hpp"
|
|
1
2
|
#include "duckdb_node.hpp"
|
|
3
|
+
#include "napi.h"
|
|
2
4
|
|
|
5
|
+
#include <iostream>
|
|
3
6
|
#include <thread>
|
|
4
7
|
|
|
5
8
|
namespace node_duckdb {
|
|
@@ -23,7 +26,7 @@ Napi::Object Connection::Init(Napi::Env env, Napi::Object exports) {
|
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
struct ConnectTask : public Task {
|
|
26
|
-
ConnectTask(Connection &
|
|
29
|
+
ConnectTask(Connection &connection, Napi::Function callback) : Task(connection, callback) {
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
void DoWork() override {
|
|
@@ -75,94 +78,28 @@ struct JSArgs {
|
|
|
75
78
|
duckdb::DataChunk *args;
|
|
76
79
|
duckdb::Vector *result;
|
|
77
80
|
bool done;
|
|
78
|
-
|
|
81
|
+
duckdb::PreservedError error;
|
|
79
82
|
};
|
|
80
83
|
|
|
81
|
-
|
|
82
|
-
Napi::EscapableHandleScope scope(env);
|
|
83
|
-
|
|
84
|
-
Napi::Array data_buffers(Napi::Array::New(env));
|
|
85
|
-
|
|
86
|
-
auto data_buffer_index = -1;
|
|
87
|
-
auto length_buffer_index = -1;
|
|
88
|
-
auto validity_buffer_index = -1;
|
|
89
|
-
|
|
90
|
-
auto validity_buffer = Napi::Buffer<uint8_t>::New(env, rows);
|
|
91
|
-
auto validity = duckdb::FlatVector::Validity(vec);
|
|
92
|
-
auto validity_ptr = validity_buffer.Data();
|
|
93
|
-
for (duckdb::idx_t row_idx = 0; row_idx < rows; row_idx++) {
|
|
94
|
-
validity_ptr[row_idx] = validity.RowIsValid(row_idx);
|
|
95
|
-
}
|
|
96
|
-
data_buffers.Set(data_buffers.Length(), validity_buffer);
|
|
97
|
-
validity_buffer_index = data_buffers.Length() - 1;
|
|
98
|
-
|
|
99
|
-
auto &vec_type = vec.GetType();
|
|
100
|
-
|
|
101
|
-
switch (vec_type.id()) {
|
|
102
|
-
case duckdb::LogicalTypeId::BOOLEAN:
|
|
103
|
-
case duckdb::LogicalTypeId::UTINYINT:
|
|
104
|
-
case duckdb::LogicalTypeId::TINYINT:
|
|
105
|
-
case duckdb::LogicalTypeId::USMALLINT:
|
|
106
|
-
case duckdb::LogicalTypeId::SMALLINT:
|
|
107
|
-
case duckdb::LogicalTypeId::INTEGER:
|
|
108
|
-
case duckdb::LogicalTypeId::UINTEGER:
|
|
109
|
-
case duckdb::LogicalTypeId::FLOAT:
|
|
110
|
-
case duckdb::LogicalTypeId::DOUBLE: {
|
|
111
|
-
auto data_buffer = Napi::Buffer<uint8_t>::New(env, rows * duckdb::GetTypeIdSize(vec_type.InternalType()));
|
|
112
|
-
// TODO this is technically not neccessary but it fixes a crash in Node 14. Some weird data ownership issue.
|
|
113
|
-
memcpy(data_buffer.Data(), duckdb::FlatVector::GetData<uint8_t>(vec),
|
|
114
|
-
rows * duckdb::GetTypeIdSize(vec_type.InternalType()));
|
|
115
|
-
|
|
116
|
-
data_buffers.Set(data_buffers.Length(), data_buffer);
|
|
117
|
-
data_buffer_index = data_buffers.Length() - 1;
|
|
118
|
-
break;
|
|
119
|
-
}
|
|
120
|
-
case duckdb::LogicalTypeId::VARCHAR: {
|
|
121
|
-
Napi::Array string_buffers(Napi::Array::New(env, rows));
|
|
122
|
-
if (copy) {
|
|
123
|
-
auto string_vec_ptr = duckdb::FlatVector::GetData<duckdb::string_t>(vec);
|
|
124
|
-
for (duckdb::idx_t row_idx = 0; row_idx < rows; row_idx++) {
|
|
125
|
-
string_buffers.Set(row_idx, validity_ptr[row_idx]
|
|
126
|
-
? Napi::String::New(env, string_vec_ptr[row_idx].GetDataUnsafe(),
|
|
127
|
-
string_vec_ptr[row_idx].GetSize())
|
|
128
|
-
: Napi::Value());
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
data_buffers.Set(data_buffers.Length(), string_buffers);
|
|
132
|
-
data_buffer_index = data_buffers.Length() - 1;
|
|
133
|
-
break;
|
|
134
|
-
}
|
|
135
|
-
default:
|
|
136
|
-
throw duckdb::NotImplementedException(vec_type.ToString());
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
Napi::Object desc(Napi::Object::New(env));
|
|
140
|
-
desc.Set("logical_type", vec_type.ToString());
|
|
141
|
-
desc.Set("physical_type", TypeIdToString(vec_type.InternalType()));
|
|
142
|
-
desc.Set("validity_buffer", validity_buffer_index);
|
|
143
|
-
desc.Set("data_buffer", data_buffer_index);
|
|
144
|
-
desc.Set("length_buffer", length_buffer_index);
|
|
145
|
-
desc.Set("data_buffers", data_buffers);
|
|
146
|
-
|
|
147
|
-
return scope.Escape(desc);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
void DuckDBNodeUDFLauncher(Napi::Env env, Napi::Function jsudf, nullptr_t *, JSArgs *jsargs) {
|
|
84
|
+
void DuckDBNodeUDFLauncher(Napi::Env env, Napi::Function jsudf, std::nullptr_t *, JSArgs *jsargs) {
|
|
151
85
|
try { // if we dont catch exceptions here we terminate node if one happens ^^
|
|
86
|
+
Napi::EscapableHandleScope scope(env);
|
|
152
87
|
|
|
153
|
-
//
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
auto arg_descr = transform_vector(env, vec, jsargs->rows, true);
|
|
158
|
-
args_descr.Set(col_idx, arg_descr);
|
|
159
|
-
}
|
|
160
|
-
auto ret_descr = transform_vector(env, *jsargs->result, jsargs->rows, false);
|
|
161
|
-
|
|
162
|
-
Napi::Object descr(Napi::Object::New(env));
|
|
88
|
+
// Set up descriptor and data arrays
|
|
89
|
+
auto descr = Napi::Object::New(env);
|
|
90
|
+
auto chunk = EncodeDataChunk(env, *jsargs->args, true, true);
|
|
91
|
+
descr.Set("args", scope.Escape(chunk));
|
|
163
92
|
descr.Set("rows", jsargs->rows);
|
|
164
|
-
|
|
165
|
-
|
|
93
|
+
auto ret = Napi::Object::New(env);
|
|
94
|
+
ret.Set("sqlType", jsargs->result->GetType().ToString());
|
|
95
|
+
auto ret_type = jsargs->result->GetType().InternalType();
|
|
96
|
+
#if NAPI_VERSION <= 5
|
|
97
|
+
if (ret_type == duckdb::PhysicalType::INT64 || ret_type == duckdb::PhysicalType::UINT64) {
|
|
98
|
+
ret_type = duckdb::PhysicalType::DOUBLE;
|
|
99
|
+
}
|
|
100
|
+
#endif
|
|
101
|
+
ret.Set("physicalType", TypeIdToString(ret_type));
|
|
102
|
+
descr.Set("ret", ret);
|
|
166
103
|
|
|
167
104
|
// actually call the UDF, or rather its vectorized wrapper from duckdb.js/Connection.prototype.register wrapper
|
|
168
105
|
jsudf({descr});
|
|
@@ -181,49 +118,87 @@ void DuckDBNodeUDFLauncher(Napi::Env env, Napi::Function jsudf, nullptr_t *, JSA
|
|
|
181
118
|
}
|
|
182
119
|
|
|
183
120
|
// transform the result back to a vector
|
|
184
|
-
auto return_validity =
|
|
185
|
-
.Get("data_buffers")
|
|
186
|
-
.ToObject()
|
|
187
|
-
.Get(ret_descr.ToObject().Get("validity_buffer"))
|
|
188
|
-
.As<Napi::Buffer<uint8_t>>();
|
|
121
|
+
auto return_validity = ret.ToObject().Get("validity").As<Napi::Uint8Array>();
|
|
189
122
|
for (duckdb::idx_t row_idx = 0; row_idx < jsargs->rows; row_idx++) {
|
|
190
123
|
duckdb::FlatVector::SetNull(*jsargs->result, row_idx, !return_validity[row_idx]);
|
|
191
124
|
}
|
|
192
125
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
126
|
+
switch (jsargs->result->GetType().id()) {
|
|
127
|
+
case duckdb::LogicalTypeId::TINYINT: {
|
|
128
|
+
auto data = ret.Get("data").As<Napi::Int8Array>();
|
|
129
|
+
auto out = duckdb::FlatVector::GetData<int8_t>(*jsargs->result);
|
|
130
|
+
memcpy(out, data.Data(), jsargs->rows * duckdb::GetTypeIdSize(ret_type));
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
case duckdb::LogicalTypeId::SMALLINT: {
|
|
134
|
+
auto data = ret.Get("data").As<Napi::Int16Array>();
|
|
135
|
+
auto out = duckdb::FlatVector::GetData<int16_t>(*jsargs->result);
|
|
136
|
+
memcpy(out, data.Data(), jsargs->rows * duckdb::GetTypeIdSize(ret_type));
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
case duckdb::LogicalTypeId::INTEGER: {
|
|
140
|
+
auto data = ret.Get("data").As<Napi::Int32Array>();
|
|
141
|
+
auto out = duckdb::FlatVector::GetData<int32_t>(*jsargs->result);
|
|
142
|
+
memcpy(out, data.Data(), jsargs->rows * duckdb::GetTypeIdSize(ret_type));
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
case duckdb::LogicalTypeId::DOUBLE: {
|
|
146
|
+
auto data = ret.Get("data").As<Napi::Float64Array>();
|
|
147
|
+
auto out = duckdb::FlatVector::GetData<double>(*jsargs->result);
|
|
148
|
+
memcpy(out, data.Data(), jsargs->rows * duckdb::GetTypeIdSize(ret_type));
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
case duckdb::LogicalTypeId::TIME:
|
|
152
|
+
case duckdb::LogicalTypeId::TIMESTAMP:
|
|
153
|
+
case duckdb::LogicalTypeId::TIMESTAMP_MS:
|
|
154
|
+
case duckdb::LogicalTypeId::TIMESTAMP_SEC:
|
|
155
|
+
case duckdb::LogicalTypeId::TIMESTAMP_NS:
|
|
156
|
+
case duckdb::LogicalTypeId::BIGINT: {
|
|
157
|
+
#if NAPI_VERSION > 5
|
|
158
|
+
auto data = ret.Get("data").As<Napi::BigInt64Array>();
|
|
159
|
+
#else
|
|
160
|
+
auto data = ret.Get("data").As<Napi::Float64Array>();
|
|
161
|
+
#endif
|
|
162
|
+
auto out = duckdb::FlatVector::GetData<int64_t>(*jsargs->result);
|
|
163
|
+
memcpy(out, data.Data(), jsargs->rows * duckdb::GetTypeIdSize(ret_type));
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
case duckdb::LogicalTypeId::UBIGINT: {
|
|
167
|
+
#if NAPI_VERSION > 5
|
|
168
|
+
auto data = ret.Get("data").As<Napi::BigUint64Array>();
|
|
169
|
+
#else
|
|
170
|
+
auto data = ret.Get("data").As<Napi::Float64Array>();
|
|
171
|
+
#endif
|
|
172
|
+
auto out = duckdb::FlatVector::GetData<uint64_t>(*jsargs->result);
|
|
173
|
+
memcpy(out, data.Data(), jsargs->rows * duckdb::GetTypeIdSize(ret_type));
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
case duckdb::LogicalTypeId::BLOB:
|
|
177
|
+
case duckdb::LogicalTypeId::VARCHAR: {
|
|
178
|
+
auto data = ret.Get("data").As<Napi::Array>();
|
|
179
|
+
auto out = duckdb::FlatVector::GetData<duckdb::string_t>(*jsargs->result);
|
|
180
|
+
for (size_t i = 0; i < data.Length(); ++i) {
|
|
181
|
+
out[i] = duckdb::string_t(data.Get(i).ToString());
|
|
182
|
+
}
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
default: {
|
|
201
186
|
for (duckdb::idx_t row_idx = 0; row_idx < jsargs->rows; row_idx++) {
|
|
202
|
-
|
|
203
|
-
duckdb::FlatVector::SetNull(*jsargs->result, row_idx, true);
|
|
204
|
-
} else {
|
|
205
|
-
auto str = return_string_array.Get(row_idx).As<Napi::String>();
|
|
206
|
-
return_string_vec_ptr[row_idx] = duckdb::StringVector::AddString(*jsargs->result, str);
|
|
207
|
-
}
|
|
187
|
+
duckdb::FlatVector::SetNull(*jsargs->result, row_idx, false);
|
|
208
188
|
}
|
|
209
|
-
} else {
|
|
210
|
-
auto return_data = ret_descr.ToObject()
|
|
211
|
-
.Get("data_buffers")
|
|
212
|
-
.ToObject()
|
|
213
|
-
.Get(ret_descr.ToObject().Get("data_buffer"))
|
|
214
|
-
.As<Napi::Buffer<uint8_t>>();
|
|
215
|
-
memcpy(duckdb::FlatVector::GetData<uint8_t>(*jsargs->result), return_data.Data(),
|
|
216
|
-
jsargs->rows * duckdb::GetTypeIdSize(jsargs->result->GetType().InternalType()));
|
|
217
189
|
}
|
|
190
|
+
}
|
|
191
|
+
} catch (const duckdb::Exception &e) {
|
|
192
|
+
jsargs->error = duckdb::PreservedError(e);
|
|
218
193
|
} catch (const std::exception &e) {
|
|
219
|
-
jsargs->error = e
|
|
194
|
+
jsargs->error = duckdb::PreservedError(e);
|
|
220
195
|
}
|
|
221
196
|
jsargs->done = true;
|
|
222
197
|
}
|
|
223
198
|
|
|
224
199
|
struct RegisterTask : public Task {
|
|
225
|
-
RegisterTask(Connection &
|
|
226
|
-
: Task(
|
|
200
|
+
RegisterTask(Connection &connection, std::string name, std::string return_type_name, Napi::Function callback)
|
|
201
|
+
: Task(connection, callback), name(std::move(name)), return_type_name(std::move(return_type_name)) {
|
|
227
202
|
}
|
|
228
203
|
|
|
229
204
|
void DoWork() override {
|
|
@@ -234,7 +209,7 @@ struct RegisterTask : public Task {
|
|
|
234
209
|
// here we can do only DuckDB stuff because we do not have a functioning env
|
|
235
210
|
|
|
236
211
|
// Flatten all args to simplify udfs
|
|
237
|
-
args.
|
|
212
|
+
args.Flatten();
|
|
238
213
|
|
|
239
214
|
JSArgs jsargs;
|
|
240
215
|
jsargs.rows = args.size();
|
|
@@ -246,8 +221,8 @@ struct RegisterTask : public Task {
|
|
|
246
221
|
while (!jsargs.done) {
|
|
247
222
|
std::this_thread::yield();
|
|
248
223
|
}
|
|
249
|
-
if (
|
|
250
|
-
|
|
224
|
+
if (jsargs.error) {
|
|
225
|
+
jsargs.error.Throw();
|
|
251
226
|
}
|
|
252
227
|
};
|
|
253
228
|
|
|
@@ -282,8 +257,8 @@ Napi::Value Connection::Register(const Napi::CallbackInfo &info) {
|
|
|
282
257
|
return env.Null();
|
|
283
258
|
}
|
|
284
259
|
|
|
285
|
-
auto udf =
|
|
286
|
-
|
|
260
|
+
auto udf = duckdb_node_udf_function_t::New(env, udf_callback, "duckdb_node_udf" + name, 0, 1, nullptr,
|
|
261
|
+
[](Napi::Env, void *, std::nullptr_t *ctx) {});
|
|
287
262
|
|
|
288
263
|
// we have to unref the udf because otherwise there is a circular ref with the connection somehow(?)
|
|
289
264
|
// this took far too long to figure out
|
|
@@ -297,8 +272,8 @@ Napi::Value Connection::Register(const Napi::CallbackInfo &info) {
|
|
|
297
272
|
}
|
|
298
273
|
|
|
299
274
|
struct UnregisterTask : public Task {
|
|
300
|
-
UnregisterTask(Connection &
|
|
301
|
-
: Task(
|
|
275
|
+
UnregisterTask(Connection &connection, std::string name, Napi::Function callback)
|
|
276
|
+
: Task(connection, callback), name(std::move(name)) {
|
|
302
277
|
}
|
|
303
278
|
|
|
304
279
|
void DoWork() override {
|
|
@@ -340,39 +315,44 @@ Napi::Value Connection::Unregister(const Napi::CallbackInfo &info) {
|
|
|
340
315
|
}
|
|
341
316
|
|
|
342
317
|
struct ExecTask : public Task {
|
|
343
|
-
ExecTask(Connection &
|
|
344
|
-
: Task(
|
|
318
|
+
ExecTask(Connection &connection, std::string sql, Napi::Function callback)
|
|
319
|
+
: Task(connection, callback), sql(std::move(sql)) {
|
|
345
320
|
}
|
|
346
321
|
|
|
347
322
|
void DoWork() override {
|
|
348
323
|
auto &connection = Get<Connection>();
|
|
349
324
|
|
|
350
325
|
success = true;
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
326
|
+
try {
|
|
327
|
+
auto statements = connection.connection->ExtractStatements(sql);
|
|
328
|
+
if (statements.empty()) {
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
355
331
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
332
|
+
for (duckdb::idx_t i = 0; i < statements.size(); i++) {
|
|
333
|
+
auto res = connection.connection->Query(move(statements[i]));
|
|
334
|
+
if (res->HasError()) {
|
|
335
|
+
success = false;
|
|
336
|
+
error = res->GetErrorObject();
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
363
339
|
}
|
|
340
|
+
} catch (duckdb::ParserException &e) {
|
|
341
|
+
success = false;
|
|
342
|
+
error = duckdb::PreservedError(e);
|
|
343
|
+
return;
|
|
364
344
|
}
|
|
365
345
|
}
|
|
366
346
|
|
|
367
347
|
void Callback() override {
|
|
368
348
|
auto env = object.Env();
|
|
369
349
|
Napi::HandleScope scope(env);
|
|
370
|
-
callback.Value().MakeCallback(object.Value(), {success ? env.Null() : Napi::String::New(env, error)});
|
|
350
|
+
callback.Value().MakeCallback(object.Value(), {success ? env.Null() : Napi::String::New(env, error.Message())});
|
|
371
351
|
};
|
|
372
352
|
|
|
373
353
|
std::string sql;
|
|
374
354
|
bool success;
|
|
375
|
-
|
|
355
|
+
duckdb::PreservedError error;
|
|
376
356
|
};
|
|
377
357
|
|
|
378
358
|
Napi::Value Connection::Exec(const Napi::CallbackInfo &info) {
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
#include "duckdb.hpp"
|
|
2
|
+
#include "duckdb_node.hpp"
|
|
3
|
+
#include "napi.h"
|
|
4
|
+
|
|
5
|
+
#include <thread>
|
|
6
|
+
|
|
7
|
+
namespace node_duckdb {
|
|
8
|
+
|
|
9
|
+
Napi::Array EncodeDataChunk(Napi::Env env, duckdb::DataChunk &chunk, bool with_types, bool with_data) {
|
|
10
|
+
Napi::Array col_descs(Napi::Array::New(env, chunk.ColumnCount()));
|
|
11
|
+
for (idx_t col_idx = 0; col_idx < chunk.ColumnCount(); col_idx++) {
|
|
12
|
+
auto col_desc = Napi::Object::New(env);
|
|
13
|
+
|
|
14
|
+
// Make sure we only have flat vectors hereafter (for now)
|
|
15
|
+
auto &chunk_vec = chunk.data[col_idx];
|
|
16
|
+
if (with_data) {
|
|
17
|
+
chunk_vec.Flatten(chunk.size());
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Do a post-order DFS traversal
|
|
21
|
+
std::vector<std::tuple<bool, duckdb::Vector *, Napi::Object, size_t, size_t>> pending;
|
|
22
|
+
pending.emplace_back(false, &chunk_vec, Napi::Object::New(env), 0, 0);
|
|
23
|
+
|
|
24
|
+
while (!pending.empty()) {
|
|
25
|
+
// Unpack DFS node
|
|
26
|
+
auto &back = pending.back();
|
|
27
|
+
auto &visited = std::get<0>(back);
|
|
28
|
+
auto &vec = std::get<1>(back);
|
|
29
|
+
auto &desc = std::get<2>(back);
|
|
30
|
+
auto &parent_idx = std::get<3>(back);
|
|
31
|
+
auto &idx_in_parent = std::get<4>(back);
|
|
32
|
+
|
|
33
|
+
// Already visited?
|
|
34
|
+
if (visited) {
|
|
35
|
+
if (pending.size() == 1) {
|
|
36
|
+
col_desc = desc;
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
std::get<2>(pending[parent_idx]).Get("children").As<Napi::Array>().Set(idx_in_parent, desc);
|
|
40
|
+
pending.pop_back();
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
visited = true;
|
|
44
|
+
auto current_idx = pending.size() - 1;
|
|
45
|
+
|
|
46
|
+
// Store types
|
|
47
|
+
auto &vec_type = vec->GetType();
|
|
48
|
+
if (with_types) {
|
|
49
|
+
desc.Set("sqlType", vec_type.ToString());
|
|
50
|
+
desc.Set("physicalType", TypeIdToString(vec_type.InternalType()));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Create validity vector
|
|
54
|
+
if (with_data) {
|
|
55
|
+
vec->Flatten(chunk.size());
|
|
56
|
+
auto &validity = duckdb::FlatVector::Validity(*vec);
|
|
57
|
+
auto validity_buffer = Napi::Uint8Array::New(env, chunk.size());
|
|
58
|
+
for (idx_t row_idx = 0; row_idx < chunk.size(); row_idx++) {
|
|
59
|
+
validity_buffer[row_idx] = validity.RowIsValid(row_idx);
|
|
60
|
+
}
|
|
61
|
+
desc.Set("validity", validity_buffer);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Create data buffer
|
|
65
|
+
switch (vec_type.id()) {
|
|
66
|
+
case duckdb::LogicalTypeId::TINYINT: {
|
|
67
|
+
if (with_data) {
|
|
68
|
+
auto array = Napi::Int8Array::New(env, chunk.size());
|
|
69
|
+
auto data = duckdb::FlatVector::GetData<int8_t>(*vec);
|
|
70
|
+
for (size_t i = 0; i < chunk.size(); ++i) {
|
|
71
|
+
array[i] = data[i];
|
|
72
|
+
}
|
|
73
|
+
desc.Set("data", array);
|
|
74
|
+
}
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
case duckdb::LogicalTypeId::SMALLINT: {
|
|
78
|
+
if (with_data) {
|
|
79
|
+
auto array = Napi::Int16Array::New(env, chunk.size());
|
|
80
|
+
auto data = duckdb::FlatVector::GetData<int16_t>(*vec);
|
|
81
|
+
for (size_t i = 0; i < chunk.size(); ++i) {
|
|
82
|
+
array[i] = data[i];
|
|
83
|
+
}
|
|
84
|
+
desc.Set("data", array);
|
|
85
|
+
}
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
case duckdb::LogicalTypeId::INTEGER: {
|
|
89
|
+
if (with_data) {
|
|
90
|
+
auto array = Napi::Int32Array::New(env, chunk.size());
|
|
91
|
+
auto data = duckdb::FlatVector::GetData<int32_t>(*vec);
|
|
92
|
+
for (size_t i = 0; i < chunk.size(); ++i) {
|
|
93
|
+
array[i] = data[i];
|
|
94
|
+
}
|
|
95
|
+
desc.Set("data", array);
|
|
96
|
+
}
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
case duckdb::LogicalTypeId::DOUBLE: {
|
|
100
|
+
if (with_data) {
|
|
101
|
+
auto array = Napi::Float64Array::New(env, chunk.size());
|
|
102
|
+
auto data = duckdb::FlatVector::GetData<double>(*vec);
|
|
103
|
+
for (size_t i = 0; i < chunk.size(); ++i) {
|
|
104
|
+
array[i] = data[i];
|
|
105
|
+
}
|
|
106
|
+
desc.Set("data", array);
|
|
107
|
+
}
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
case duckdb::LogicalTypeId::BIGINT:
|
|
111
|
+
case duckdb::LogicalTypeId::TIME:
|
|
112
|
+
case duckdb::LogicalTypeId::TIME_TZ:
|
|
113
|
+
case duckdb::LogicalTypeId::TIMESTAMP_MS:
|
|
114
|
+
case duckdb::LogicalTypeId::TIMESTAMP_NS:
|
|
115
|
+
case duckdb::LogicalTypeId::TIMESTAMP_SEC:
|
|
116
|
+
case duckdb::LogicalTypeId::TIMESTAMP: {
|
|
117
|
+
if (with_data) {
|
|
118
|
+
#if NAPI_VERSION > 5
|
|
119
|
+
auto array = Napi::BigInt64Array::New(env, chunk.size());
|
|
120
|
+
auto data = duckdb::FlatVector::GetData<int64_t>(*vec);
|
|
121
|
+
#else
|
|
122
|
+
auto array = Napi::Float64Array::New(env, chunk.size());
|
|
123
|
+
auto data = duckdb::FlatVector::GetData<int64_t>(*vec);
|
|
124
|
+
#endif
|
|
125
|
+
for (size_t i = 0; i < chunk.size(); ++i) {
|
|
126
|
+
array[i] = data[i];
|
|
127
|
+
}
|
|
128
|
+
desc.Set("data", array);
|
|
129
|
+
}
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
case duckdb::LogicalTypeId::UBIGINT: {
|
|
133
|
+
if (with_data) {
|
|
134
|
+
#if NAPI_VERSION > 5
|
|
135
|
+
auto array = Napi::BigUint64Array::New(env, chunk.size());
|
|
136
|
+
auto data = duckdb::FlatVector::GetData<uint64_t>(*vec);
|
|
137
|
+
#else
|
|
138
|
+
auto array = Napi::Float64Array::New(env, chunk.size());
|
|
139
|
+
auto data = duckdb::FlatVector::GetData<int64_t>(*vec);
|
|
140
|
+
#endif
|
|
141
|
+
for (size_t i = 0; i < chunk.size(); ++i) {
|
|
142
|
+
array[i] = data[i];
|
|
143
|
+
}
|
|
144
|
+
desc.Set("data", array);
|
|
145
|
+
}
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
case duckdb::LogicalTypeId::BLOB:
|
|
149
|
+
case duckdb::LogicalTypeId::VARCHAR: {
|
|
150
|
+
if (with_data) {
|
|
151
|
+
auto array = Napi::Array::New(env, chunk.size());
|
|
152
|
+
auto data = duckdb::FlatVector::GetData<duckdb::string_t>(*vec);
|
|
153
|
+
for (size_t i = 0; i < chunk.size(); ++i) {
|
|
154
|
+
array.Set(i, data[i].GetString());
|
|
155
|
+
}
|
|
156
|
+
desc.Set("data", array);
|
|
157
|
+
}
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
case duckdb::LogicalTypeId::STRUCT: {
|
|
161
|
+
auto child_count = duckdb::StructType::GetChildCount(vec_type);
|
|
162
|
+
auto &entries = duckdb::StructVector::GetEntries(*vec);
|
|
163
|
+
desc.Set("children", Napi::Array::New(env, child_count));
|
|
164
|
+
for (size_t i = 0; i < child_count; ++i) {
|
|
165
|
+
auto c = child_count - 1 - i;
|
|
166
|
+
auto &entry = entries[c];
|
|
167
|
+
auto desc = Napi::Object::New(env);
|
|
168
|
+
auto name = duckdb::StructType::GetChildName(vec_type, c);
|
|
169
|
+
desc.Set("name", name);
|
|
170
|
+
pending.emplace_back(false, entry.get(), desc, current_idx, i);
|
|
171
|
+
}
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
default:
|
|
175
|
+
Napi::TypeError::New(env, "Unsupported UDF argument type " + vec->GetType().ToString())
|
|
176
|
+
.ThrowAsJavaScriptException();
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
col_descs.Set(col_idx, col_desc);
|
|
181
|
+
}
|
|
182
|
+
return col_descs;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
} // namespace node_duckdb
|