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/database.cpp
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#include "duckdb_node.hpp"
|
|
2
|
+
#include "napi.h"
|
|
2
3
|
#include "parquet-amalgamation.hpp"
|
|
3
4
|
|
|
4
5
|
namespace node_duckdb {
|
|
@@ -22,23 +23,47 @@ Napi::Object Database::Init(Napi::Env env, Napi::Object exports) {
|
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
struct OpenTask : public Task {
|
|
25
|
-
OpenTask(Database &database_, std::string filename_,
|
|
26
|
-
|
|
26
|
+
OpenTask(Database &database_, std::string filename_, duckdb::AccessMode access_mode_, Napi::Object config_,
|
|
27
|
+
Napi::Function callback_)
|
|
28
|
+
: Task(database_, callback_), filename(filename_) {
|
|
29
|
+
|
|
30
|
+
duckdb_config.options.access_mode = access_mode_;
|
|
31
|
+
Napi::Env env = database_.Env();
|
|
32
|
+
Napi::HandleScope scope(env);
|
|
33
|
+
|
|
34
|
+
if (!config_.IsUndefined()) {
|
|
35
|
+
const Napi::Array config_names = config_.GetPropertyNames();
|
|
36
|
+
|
|
37
|
+
for (duckdb::idx_t config_idx = 0; config_idx < config_names.Length(); config_idx++) {
|
|
38
|
+
std::string key = config_names.Get(config_idx).As<Napi::String>();
|
|
39
|
+
std::string val = config_.Get(key).As<Napi::String>();
|
|
40
|
+
auto config_property = duckdb::DBConfig::GetOptionByName(key);
|
|
41
|
+
if (!config_property) {
|
|
42
|
+
Napi::TypeError::New(env, "Unrecognized configuration property" + key).ThrowAsJavaScriptException();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
duckdb_config.SetOption(*config_property, duckdb::Value(val));
|
|
47
|
+
} catch (std::exception &e) {
|
|
48
|
+
Napi::TypeError::New(env, "Failed to set configuration option " + key + ": " + e.what())
|
|
49
|
+
.ThrowAsJavaScriptException();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
27
54
|
}
|
|
28
55
|
|
|
29
56
|
void DoWork() override {
|
|
30
57
|
try {
|
|
31
|
-
duckdb::
|
|
32
|
-
if (read_only) {
|
|
33
|
-
config.access_mode = duckdb::AccessMode::READ_ONLY;
|
|
34
|
-
}
|
|
35
|
-
Get<Database>().database = duckdb::make_unique<duckdb::DuckDB>(filename, &config);
|
|
58
|
+
Get<Database>().database = duckdb::make_unique<duckdb::DuckDB>(filename, &duckdb_config);
|
|
36
59
|
duckdb::ParquetExtension extension;
|
|
37
60
|
extension.Load(*Get<Database>().database);
|
|
38
61
|
success = true;
|
|
39
62
|
|
|
63
|
+
} catch (const duckdb::Exception &ex) {
|
|
64
|
+
error = duckdb::PreservedError(ex);
|
|
40
65
|
} catch (std::exception &ex) {
|
|
41
|
-
error = ex
|
|
66
|
+
error = duckdb::PreservedError(ex);
|
|
42
67
|
}
|
|
43
68
|
}
|
|
44
69
|
|
|
@@ -48,7 +73,7 @@ struct OpenTask : public Task {
|
|
|
48
73
|
|
|
49
74
|
std::vector<napi_value> args;
|
|
50
75
|
if (!success) {
|
|
51
|
-
args.push_back(Utils::CreateError(env, error));
|
|
76
|
+
args.push_back(Utils::CreateError(env, error.Message()));
|
|
52
77
|
} else {
|
|
53
78
|
args.push_back(env.Null());
|
|
54
79
|
}
|
|
@@ -59,22 +84,35 @@ struct OpenTask : public Task {
|
|
|
59
84
|
}
|
|
60
85
|
|
|
61
86
|
std::string filename;
|
|
62
|
-
|
|
63
|
-
|
|
87
|
+
duckdb::DBConfig duckdb_config;
|
|
88
|
+
duckdb::PreservedError error;
|
|
64
89
|
bool success = false;
|
|
65
90
|
};
|
|
66
91
|
|
|
67
|
-
Database::Database(const Napi::CallbackInfo &info)
|
|
92
|
+
Database::Database(const Napi::CallbackInfo &info)
|
|
93
|
+
: Napi::ObjectWrap<Database>(info), task_inflight(false), env(info.Env()) {
|
|
68
94
|
auto env = info.Env();
|
|
95
|
+
|
|
69
96
|
if (info.Length() < 1 || !info[0].IsString()) {
|
|
70
97
|
Napi::TypeError::New(env, "Database location expected").ThrowAsJavaScriptException();
|
|
71
98
|
return;
|
|
72
99
|
}
|
|
73
100
|
std::string filename = info[0].As<Napi::String>();
|
|
74
101
|
unsigned int pos = 1;
|
|
102
|
+
|
|
103
|
+
duckdb::AccessMode access_mode = duckdb::AccessMode::AUTOMATIC;
|
|
104
|
+
|
|
75
105
|
int mode = 0;
|
|
76
106
|
if (info.Length() >= pos && info[pos].IsNumber() && Utils::OtherIsInt(info[pos].As<Napi::Number>())) {
|
|
77
107
|
mode = info[pos++].As<Napi::Number>().Int32Value();
|
|
108
|
+
if (mode == DUCKDB_NODEJS_READONLY) {
|
|
109
|
+
access_mode = duckdb::AccessMode::READ_ONLY;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
Napi::Object config;
|
|
114
|
+
if (info.Length() >= pos && info[pos].IsObject() && !info[pos].IsFunction()) {
|
|
115
|
+
config = info[pos++].As<Napi::Object>();
|
|
78
116
|
}
|
|
79
117
|
|
|
80
118
|
Napi::Function callback;
|
|
@@ -82,7 +120,11 @@ Database::Database(const Napi::CallbackInfo &info) : Napi::ObjectWrap<Database>(
|
|
|
82
120
|
callback = info[pos++].As<Napi::Function>();
|
|
83
121
|
}
|
|
84
122
|
|
|
85
|
-
Schedule(env, duckdb::make_unique<OpenTask>(*this, filename,
|
|
123
|
+
Schedule(env, duckdb::make_unique<OpenTask>(*this, filename, access_mode, config, callback));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
Database::~Database() {
|
|
127
|
+
Napi::MemoryManagement::AdjustExternalMemory(env, -bytes_allocated);
|
|
86
128
|
}
|
|
87
129
|
|
|
88
130
|
void Database::Schedule(Napi::Env env, std::unique_ptr<Task> task) {
|
|
@@ -93,17 +135,15 @@ void Database::Schedule(Napi::Env env, std::unique_ptr<Task> task) {
|
|
|
93
135
|
Process(env);
|
|
94
136
|
}
|
|
95
137
|
|
|
96
|
-
static void
|
|
138
|
+
static void TaskExecuteCallback(napi_env e, void *data) {
|
|
97
139
|
auto holder = (TaskHolder *)data;
|
|
98
140
|
holder->task->DoWork();
|
|
99
141
|
}
|
|
100
142
|
|
|
101
|
-
static void
|
|
143
|
+
static void TaskCompleteCallback(napi_env e, napi_status status, void *data) {
|
|
102
144
|
std::unique_ptr<TaskHolder> holder((TaskHolder *)data);
|
|
103
145
|
holder->db->TaskComplete(e);
|
|
104
|
-
|
|
105
|
-
holder->task->Callback();
|
|
106
|
-
}
|
|
146
|
+
holder->task->DoCallback();
|
|
107
147
|
}
|
|
108
148
|
|
|
109
149
|
void Database::TaskComplete(Napi::Env env) {
|
|
@@ -112,6 +152,16 @@ void Database::TaskComplete(Napi::Env env) {
|
|
|
112
152
|
task_inflight = false;
|
|
113
153
|
}
|
|
114
154
|
Process(env);
|
|
155
|
+
|
|
156
|
+
if (database) {
|
|
157
|
+
// Bookkeeping: tell node (and the node GC in particular) how much
|
|
158
|
+
// memory we're using, such that it can make better decisions on when to
|
|
159
|
+
// trigger collections.
|
|
160
|
+
auto &buffer_manager = duckdb::BufferManager::GetBufferManager(*database->instance);
|
|
161
|
+
auto current_bytes = buffer_manager.GetUsedMemory();
|
|
162
|
+
Napi::MemoryManagement::AdjustExternalMemory(env, current_bytes - bytes_allocated);
|
|
163
|
+
bytes_allocated = current_bytes;
|
|
164
|
+
}
|
|
115
165
|
}
|
|
116
166
|
|
|
117
167
|
void Database::Process(Napi::Env env) {
|
|
@@ -131,8 +181,8 @@ void Database::Process(Napi::Env env) {
|
|
|
131
181
|
holder->task = move(task);
|
|
132
182
|
holder->db = this;
|
|
133
183
|
|
|
134
|
-
napi_create_async_work(env,
|
|
135
|
-
holder, &holder->request);
|
|
184
|
+
napi_create_async_work(env, nullptr, Napi::String::New(env, "duckdb.Database.Task"), TaskExecuteCallback,
|
|
185
|
+
TaskCompleteCallback, holder, &holder->request);
|
|
136
186
|
|
|
137
187
|
napi_queue_async_work(env, holder->request);
|
|
138
188
|
}
|
|
@@ -157,7 +207,7 @@ Napi::Value Database::Serialize(const Napi::CallbackInfo &info) {
|
|
|
157
207
|
}
|
|
158
208
|
|
|
159
209
|
struct WaitTask : public Task {
|
|
160
|
-
WaitTask(Database &
|
|
210
|
+
WaitTask(Database &database, Napi::Function callback) : Task(database, callback) {
|
|
161
211
|
}
|
|
162
212
|
|
|
163
213
|
void DoWork() override {
|
|
@@ -171,7 +221,7 @@ Napi::Value Database::Wait(const Napi::CallbackInfo &info) {
|
|
|
171
221
|
}
|
|
172
222
|
|
|
173
223
|
struct CloseTask : public Task {
|
|
174
|
-
CloseTask(Database &
|
|
224
|
+
CloseTask(Database &database, Napi::Function callback) : Task(database, callback) {
|
|
175
225
|
}
|
|
176
226
|
|
|
177
227
|
void DoWork() override {
|